首先 swoole 是 php 的一个扩展程序php
swoole 是一个为 php 用 c 和 c++ 编写的基于事件的高性能异步 & 协程并行网络通讯引擎前端
swoole 是一个多进程模型的框架,当启动一个进程 swoole 应用时,一共会建立 2+n+m 个进程,n 为 worker 进程数,m 为 TaskWorker 进程数,1 个 master 进程和一个 manager 进程,关系以下图所示nginx
Master 进程为主进程,该进程会建立 Manager 进程、Reactor 线程等工做进 / 线程laravel
一、Reactor 线程:c++
负责维护客户端 TCP
链接、处理网络 IO
、处理协议、收发数据程序员
彻底是异步非阻塞的模式web
所有为 C
代码,除 Start
/Shudown
事件回调外,不执行任何 PHP 代码ajax
将 TCP
客户端发来的数据缓冲、拼接、拆分红完整的一个请求数据包算法
Reactor
以多线程的方式运行sql
二、Worker 进程:
接受由 Reactor
线程投递的请求数据包,并执行 PHP
回调函数处理数据
生成响应数据并发给 Reactor
线程,由 Reactor
线程发送给 TCP
客户端
能够是异步非阻塞模式,也能够是同步阻塞模式
Worker
以多进程的方式运行
三、TaskWorker 进程 :
接受由 Worker
进程经过 swoole_server->task/taskwait
方法投递的任务
处理任务,并将结果数据返回(使用 swoole_server->finish
)给 Worker
进程
彻底是同步阻塞模式
TaskWorker
以多进程的方式运行
网络通讯引擎,是为 php 提供网络通讯能力的,传统的 php 程序都是启动 php-fpm,前边再有一层 nginx 或者 apache,打开浏览器访问就 OK,可是从浏览器访问到服务器这一阶段涉及到了网络强求,可是这一阶段跟 php 脚本没有任何的关系,php 只须要处理好数据生成须要展现的内容就完成使命了,声明周期当中,请求到来前和请求完成后都没有 php 脚本什么事,而 swoole 提供的一大能力就是扩展了 php 的生命周期,无需 php-fpm 或者 nginx 或者 apache 之类的工具帮助就能够启动一个 web 服务,而且从服务启动前,启动后,连接进入,请求到来,请求结束,连接切断,服务终止都在 php 脚本的掌控之中,这样的话 php 脚本就会涉及到大量的网络通信处理,而这个网络通信处理的能力正是来源于 swoole! 网络通讯引擎,是为 php 提供网络通讯能力的,传统的 php 程序都是启动 php-fpm,前边再有一层 nginx 或者 apache,打开浏览器访问就 OK,可是从浏览器访问到服务器这一阶段涉及到了网络强求,可是这一阶段跟 php 脚本没有任何的关系,php 只须要处理好数据生成须要展现的内容就完成使命了,声明周期当中,请求到来前和请求完成后都没有 php 脚本什么事,而 swoole 提供的一大能力就是扩展了 php 的生命周期,无需 php-fpm 或者 nginx 或者 apache 之类的工具帮助就能够启动一个 web 服务,而且从服务启动前,启动后,连接进入,请求到来,请求结束,连接切断,服务终止都在 php 脚本的掌控之中,这样的话 php 脚本就会涉及到大量的网络通信处理,而这个网络通信处理的能力正是来源于 swoole!
同步:
就拿读取文件内容来讲吧
file_get_contents () 执行完才能执行下边的代码 这样就很容易形成程序的阻塞
不然下边的代码就没法输出文件的内容
传统 php 都是这样阻塞式的顺序执行的
这是常见的同步编程
异步:
代码在执行到 ajax 的时候,函数会直接返回,你立刻就能够看到屏幕上打印出的 lol
这就是异步,这样你永远不会被 IO 阻塞,可是它带来了新的问题,在你运行到 lol 以后你就不知道如今代码运行到哪里去了,你只能等待回调被触发,而后屏幕上打印响应的 log, 它的执行不是单层顺序的,而是嵌套的
若是在业务代码当中 这样层层嵌套可读性可想而知
固然这是前端异步请求后端接口
swoole 当中处理异步回调嵌套使用的是协程
你知道什么叫协程吗?你知道线程是干啥的吗?你又知道进程吗?
若是想深刻了解 swoole 的强大之处 你还得要了解传统 php 的 lnmp 环境的整套运行机制,这些你都了解吗?
目前 swoole 当中的异步也是协程化的,因此你必须充分理解协程究竟是个什么东西!
到底什么是协程?
通俗的说,协程就是一段段协做方式执行的程序,协做来完成一件事,协做就是协同做业。咱们知道团队协同来作事,比我的单独来作事,效率确定要高,由于团队协同能够发挥各成员的能动性、优点互补。这是拿人来比喻。咱们拿作事来比喻举个例子:好比咱们作饭,好比有如下环节洗菜、切菜、烧水、炒菜、煮米饭,人做为主体来操做,那么若是循序渐进的作,先烧水,再洗菜,在切菜,再炒菜,再煮饭,那这顿饭要作很长时间好比总共 30 分钟吧,若是咱们经过协同方式,先烧水,放灶火上就能够作其余洗菜、切菜的准备,再煮米饭,而后再来洗菜、切菜,再查看煮米饭,再炒菜,…,如此循环往复切换,最后水烧好,米饭也煮好了,菜也炒好了,饭也 OK 了,这样咱们耗时可能只有 10-15 分钟,看到了吗,这就是生活中的 “协程”,由人来合理调度安排不一样的环节,充分利用各类不一样的资源和时间,来达到提升效率。协程是计算机程序,调用的则是不一样的程序,处理者主要由 CPU 完成,处理对象是各类 IO 资源,处理的方式是不一样的语言编写的程序。咱们知道,CPU 能够调度不一样的程序,让程序调用不一样的 IO 资源,最初的进程是经过 CPU 频繁的切换来完成调用程序的,是操做系统按必定算法分配的时间片抢占被动方式来切换的,未考虑程序实际执行情况,这样切换程序会带来必定问题,而协程做为一种新的工做模式,可让程序协做方式来执行,在须要使用 CPU 时,交给程序处理,遇到耗时的 IO 资源操做时会让出 CPU,交给处理其余程序,这样互相协做来执行,而不是抢占式的,就像交通规则,你们都遵照按必定规则礼让先行,不随便抢道,协同方式,程序都会执行的良好。
咱们来看具体的案例:
go(function () { echo "hello go1 \n"; }); echo "hello main \n"; go(function () { echo "hello go2 \n"; });
上面的代码执行结果:
root@b98940b00a9b /v/w/c/p/swoole# php co.php hello go1 hello main hello go2
执行结果和咱们平时写代码的顺序,好像没啥区别。实际执行过程:
运行此段代码,系统启动一个新进程
遇到 go()
, 当前进程中生成一个协程,协程中输出 heelo go1
, 协程退出
进程继续向下执行代码,输出 hello main
再生成一个协程,协程中输出 heelo go2
, 协程退出
咱们来稍微改一改,体验协程的调度:
use Co; go(function () { Co::sleep(1); // 只新增了一行代码 echo "hello go1 \n"; }); echo "hello main \n"; go(function () { echo "hello go2 \n"; });
\Co::sleep () 函数功能和 sleep () 差很少,可是它模拟的是 IO 等待 (IO 后面会细讲). 执行的结果以下:
root@b98940b00a9b /v/w/c/p/swoole# php co.php hello main hello go2 hello go1
怎么不是顺序执行的呢?实际执行过程:
运行此段代码,系统启动一个新进程
遇到 go()
, 当前进程中生成一个协程
协程中遇到 IO 阻塞 (这里是 Co::sleep()
模拟出的 IO 等待), 协程让出控制,进入协程调度队列
进程继续向下执行,输出 hello main
执行下一个协程,输出 hello go2
以前的协程准备就绪,继续执行,输出 hello go1
到这里,已经能够看到 swoole 中 协程与进程的关系 , 以及 协程的调度 , 咱们再改一改刚才的程序
go(function () { Co::sleep(1); echo "hello go1 \n"; }); echo "hello main \n"; go(function () { Co::sleep(1); echo "hello go2 \n"; });
我想你已经知道输出是什么样子了:
root@b98940b00a9b /v/w/c/p/swoole# php co.php hello main hello go1 hello go2
协程快在哪?减小 IO 阻塞致使的性能损失
你们可能听到使用协程的最多的理由,可能就是 协程快. 那看起来和平时写得差很少的代码,为何就要快一些呢?一个常见的理由是,能够建立不少个协程来执行任务,因此快. 这种说法是对的,不过还停留在表面
首先,通常的计算机任务分为 2 种
CPU 密集型,好比加减乘除等科学计算
IO 密集型,好比网络请求,文件读写等
其次,高性能相关的 2 个概念
并行:同一个时刻,同一个 CPU 只能执行同一个任务,要同时执行多个任务,就须要有多个 CPU 才行
并发:因为 CPU 切换任务很是快,快到人类能够感知的极限,就会有不少任务 同时执行 的错觉
了解了这些,咱们再来看协程,协程适合的是 IO 密集型 应用,由于协程在 IO 阻塞 时会自动调度,减小 IO 阻塞致使的时间损失!
协程在遇到 IO 阻塞的时候会让出 cpu 的控制权,其余协程拿到去执行其余协程的任务,当 IO 阻塞过去以后回过头来继续往下执行!
要点:
协程在阻塞的时候只是阻塞了当前这个协程 并不会阻塞整个的进程 由于协程是在线程内部的,即便阻塞了也会让出控制权,挂起,等待当前协程的 IO 不阻塞在回过头来继续执行,也就是同步的代码完成了异步的功能!至关强悍!
从宏观的角度看,程序员搞出来的多个协程在不发生任何协程阻塞的前提是是顺序执行的 一旦发生阻塞 你能够把多个协程理解为并行的 同时在执行的!
协程是在单进程单线程当中实现的 你能够在里面实现成千上万的协程 而且效果极高! 每一个协程去干不一样的事!协做制的无需加锁没有抢占,串行的!什么叫串行呢?每次执行一个协程 遇到 IO 阻塞 挂起 执行接下来的程序 可能仍是个协程 若是再遇到 IO 阻塞再挂起 继续往下执行 当 IO 阻塞完成回过头来继续往下执行没执行完的协程程序 每次都是一个协程在执行,串行化的!
协程之间每秒能够进行百万千万次切换! 线程之间切换须要加锁 加锁就很浪费资源!进程间切换更浪费资源,由于上线文很大!更多详细内容请自行百度!
协程很小切换还快 每秒百万千万级别的切换 因此 一个进程里面 只要你的内存够用 你就能够无止境的创造协程出来干事情!
事件驱动和异步为 swoole 提供了高性能 而协程解决了异步回调代码嵌套的问题 提升了代码可读性和维护性 也是 swoole 最大的特点!
你能够随意建立一个 http tcp websocket http2 服务 而且能轻松承载成千上万的请求
这个能够去官网 看如何建立 http 服务 tcp 服务 websocket 服务
websocket 是 http 升级而来的 建立了 websocket 服务就自带了 http 服务
建立好服务 直接 start 就能够运行一个 http 服务或者其余 tcp 等的服务了 而无需 nginx apache 的任何参与!
有服务端必有客户端 咱们能够在代码里面经过
new Swoole\Coroutine\Http\Client(127.0.0.1,9501);
去连接 http 服务器
固然其余的也同样 本身去看手册 这里只是说明 swoole 有多么的强大
通道(channel)是协程之间通讯交换数据的惟一渠道,而协程 + 通道的开发组合即为著名的 csp 编程模型
在 swoole 当中 channel 经常使用于链接池的实现和协程并发的调度
如图所示 第一个协程执行完成以后咱们会往 channel 通道当中 push 一个元素 第二个也是 固然第一个必定是 IO 阻塞的 第二个没有 咱们在 for 循环里面 获取 channel 里面的值的时候因为第一个阻塞 $chan->pop () 也是阻塞的 由于总体都是在一个协程里面 只有当大的协程里面的两个小协程都完成了 这里的 $chan->pop 才会执行 接触阻塞 最后才会执行 echo 语句! 这是 swoole 当中协程并发的一个很好的案例应用
毫秒定时器是异步回调的方式来实现的!
还可使用协程方式 采用同步阻塞的方式来实现定时器!
以前用 sleep 会阻塞整个进程 如今你在协程里面搞 Co:sleep (0.1) 阻塞的是当前协程 而不会阻塞整个进程!
好了各位,以上就是这篇文章的所有内容了,能看到这里的人呀,都是人才。以前说过,PHP方面的技术点不少,也是由于太多了,实在是写不过来,写过来了你们也不会看的太多,因此我这里把它整理成了PDF和文档,若是有须要的能够
更多学习内容能够访问【对标大厂】精品PHP架构师教程目录大全,只要你能看完保证薪资上升一个台阶(持续更新)
以上内容但愿帮助到你们,不少PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提高,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货须要的能够免费分享给你们,须要的能够加入个人 PHP技术交流群