于swoole 4.0全新的PHP编程模式



上面是一段PHP代码,其中2个函数的执行时间都是1秒,整段代码执行完成需要2秒。要想将这种串行执行方式转换为并行执行,在PHP中可以通过创建多进程来执行每个函数,单个进程执行单个函数,这样在1秒钟能就能执行完上面的代码。虽然在Java中多线程应用很普遍,但是很可惜PHP并不支持多线程。



除开多线程和多进程,还有一种方式也能实现并行编程,那就是协程(Coroutine),这也是GO语言的重要特性。协程的并发量相对多线程和多进程要高出很多,同一个进程内可以创建几十万甚至上百万个协程,且只占用少量的内存空间。线程和进程由操作系统调度,是非常昂贵的系统资源,创建过多的话,在上下文保存和进行切换的开销上会很大。



这里将前面的代码以协程的形式进行了重写,执行的时候会创建两个协程,执行时间为1秒。虽然执行效果和多进程或多线程一样,但实现原理有所不同。协程中这两个函数的执行基于一种自动让出的机制,一旦执行函数遇到IO操作,就会自动让出当前执行栈交由下一个函数执行,在IO完成之后再恢复协程栈。


PHP由于自身的天然缺陷无法支持多线程,所以我们绕开了它直接在swoft 4.0中实现了协程。但由于针对CPU密集操作只能利用到一个核,所以在使用协程的时候还是会利用多进程的方式来复用CPU的多核操作。


协程最大的好处在于能够提供极大的并发,因为它仅占用内存,不存在进程/线程切换开销,单个进程就可开启50w个协程。


我们在swoft 1.0的时候采用的技术方案和node.js的异步回调一样,在2.0的时候开始尝试实现协程,但是存在一些缺陷——协程不能用在所有的函数上,只能用在一些已经预定好的函数上。这是由于PHP有一些动态的特性,比如将URL映射到一个类方法上,这种场景下执行2.0的协程程序就会崩溃。4.0的时候我们对此做了一些优化,基于微信开源的库重新实现了协程方案,这时的协程就达到了在Go语言中的效果。



上面展示的就是PHP中使用协程的三种方式。左上的代码通过循环的方式创建了10个协程,下面这段则是在协程中执行读文件的操作,且内部还嵌套了两个协程,它们之间是相互依赖的关系。右边的代码直接创建了3个协程,每个协程的执行逻辑都不一样。


有了协程之后,就会涉及到如何管理协程或数据通信的问题。在Java多线程中,线程之间的通信可能会使用锁或者数据结构的方式解决,在协程编程中一般使用的chan的方式管理。


协程是一个用户态的线程,同一时间执行的协程只有一个。这一点和多线程不同,创建出来的多个线程都会并行执行。



左边这段代码是协程编程,它会读取一个全局的数组,当协程1读取数组的时候,协程2其实没有运行,直到协程1遇到IO操作释放了控制权,协程2才会恢复再去读全局变量,这样就完全不用加锁了。


右边是线程编程,可以看到如果程序要读取全局临界资源就一定要加锁,要不断的lock、unlock。


Chan有点类似队列,不过它自带了协程调度能力。


多线程读取队列时,会有生产者和消费者。在队列内存占用过多无法再写入的情况下,生产者还是会持续写入,一般的解决方案是进行盲等,比如让生产者sleep一段时间然后再去写入。在队列无数据可返回的情况下,一种方案是让消费者盲等,CPU死循环去等待,不过这样会占满CPU。一般的方案是在发现无数据返回的时候sleep一段时间,之后再尝试读取。


协程编程中可以通过chan来完成协程调度。当生产者发现容量不足的时候会展示挂起当前协程,直到有消费者拿走一些数据之后才会唤醒这个协程。消费者的读取机制也是一样的,无可用数据时就挂起,一旦生产者push数据后再唤醒。


由于PHP的动态语言特性,所以可以向chan中push任意的PHP变量,无论是对象还是数组。Chan的底层基于引用计数管理,完全没有内存拷贝,除了标量类型是直接复制之外,包括数组、对象这些复杂的数据结构都是用的引用计数管理。像Go语言一样,我们也提供了chan::select用来对多个chan进行读写判读。



协程框架swoft的介绍


Swoft是基于协程实现的web开发框架。它借鉴了spring Cloud做了完全组件化的实现,里面很多功能都是一个小的组件,当然也可以用自定义的组件替换内置的组件。该框架也提供了依赖注入、容器、连接池、AOP,除了应用在web领域之外,还能够用在微服务上。



上面两行命令分别是用来创建swoft工程和引入相关组件。


目前swoft支持3种服务器,swoft-http-srever 、swoft-websocket-server swoft-rpc-server。 第一个用来做主流的web应用程序,第二个是长连接通信服务,最后是微服务领域的RPC服务。



通过命令行脚本能够直接启用以上3种服务,这里也提供了一些常用的脚本工具。



Swoft参考Java的Spring框架,用了很多注解编程的方式。对于Web开发中的URL映射,可以直接通过注解的方式写Route。能够自动将URL映射到当前Controller方法中,URL中的参数也会自动带入类方法中。


基于swoft协程框架进行PHP微服务治理


Swoft自带了一些微服务常用的组件,包括服务注册、熔断、降级、负载均衡、接口多版本等。



Swoft的服务注册与发现是基于Google开源的consul,要使用consul需要添加一些配置,定义服务提供方和接入方的key。然后在前面提到的命令行脚本调用RPC start就会自动将我们的服务器节点注册到consul服务器中。



Swoft的接口声明也是基于注解的方式,如上图所示通过注解定义了service指向的服务以及调用的接口,调用的时候会映射到对应的方法。


swoft的熔断机制中失败超过一定次数,服务就关闭,成功的话,服务重新连接。



这段代码是关于熔断器的调用,首先确定熔断器的名词,正常情况下调用handler,失败的话就调用fallback进行一些处理。


这里关于微服务的介绍可能比较简要,其实是因为做服务治理更多的还是要用成熟的框架。PHP方面我们推荐使用Tars,这是腾讯开源的微服务治理框架,基于WUP结构定义文件,可以自动生成接口骨架代码,有着完整的服务治理方案,自带发布、运维、监控、弹性伸缩体系。


©著作权归作者所有:来自51CTO博客作者mob604756ef1373的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. Ansible Playbook详解
  2. 我的开源项目——Windows PE和Linux ELF可执行文件解析工具
  3. 关于Cisco Smart Install存在远程命令执行漏洞的情况通报
  4. java线程池模型
  5. 3.2 Ansible Playbooks 高级二
  6. 3.0 Ansible Playbooks基础
  7. SQL on Hadoop 技术分析(二)
  8. Hive高级优化 | 面试及调优必读
  9. Structured Streaming VS Flink

随机推荐

  1. Android P窗口机制之Window加载流程
  2. shape 的使用xml
  3. asdsad
  4. 从零开始学习Android开发
  5. [Android(安卓)API学习]Data Storage胡乱
  6. 怎么让Linearlayout里面的textview垂直居
  7. 《疯狂Android讲义》第二版目录
  8. Android内存泄漏检测工具大全
  9. Android(安卓)OCR之tesseract
  10. Android TextView的一些小知识