协程
- 什么是协程?协程与线程的区别?
协程可以简单理解为线程,只不过这个线程是用户态的,不需要操作系统参与,创建销毁和切换的成本非常低。从技术的角度来说,“协程就是可以暂停执行的函数”。
协程是组织好的代码流程,线程是被分割的CPU资源,协程需要线程来承载运行,线程是协程的资源
- 什么是协程容器
使用 Coroutine::create
或 go
(前一个方法的别名)方法创建协程,在创建的协程中才能使用协程 API,而协程必须创建在协程容器里面,参考协程容器。
协程调度
决定让CPU执行哪个协程的代码决断过程就是协程调度
- 在执行某个协程代码的过程中遇到了
Co::sleep()
或者产生了网络 IO ,如数据库查询等,Swoole 就会把这个连接的fd 防盗 EventLoop 中。 - 让出这个协程的CPU给其他协程使用,即
yield
挂起 - 等待MySQL返回数据后继续执行这个协程,即
resume
恢复
高性能共享内存 Table
由于 PHP 语言不支持多线程,因此 Swoole 使用多进程模式,在多进程模式下存在进程内存隔离,在工作进程内修改 global 全局变量和超全局变量时,在其他进程是无效的。
- 设置 worker_num=1 时,不存在进程隔离,可以使用全局变量保存数据
服务器(协程)
异步风格的服务器无法保证事件的顺序,例如需要先连接后接收的TCP
服务
tips:可以动态的开启关闭服务,异步风格的服务在 start() 被调用之后就什么也干不了了,而协程风格的可以动态开启关闭服务。
缺点:
协程风格的服务不会自动创建多个进程,需要配合
Process\Pool
模块使用才能利用多核。- 协程风格服务其实是对
Co\Socket
模块的封装,所以用协程风格的需要对socket
编程有一定经验。 - 目前封装层级没有异步风格服务器那么高,有些东西需要自己手动实现,比如
reload
功能需要自己监听信号来做逻辑。TCP服务器
Swoole\Coroutine\Server
是一个完全<u>协程化</u>的类,用于创建协程 TCP 服务器,支持 TCP 和 unixSocket
类型。
一键协程化
- 什么是HOOK
这里的HOOK类似于函数库,使用了HOOK,就可以在协程中直接使用该HOOK下的方法
协程编程须知
编程范式
- 协程内部禁止使用全局变量
- 协程使用 use 关键字引入外部变量到当前作用域禁止使用引用
- 协程之间通讯必须使用 channel
- 禁止使用exit退出脚本
异常处理
协程编程中可直接使用 try/catch
处理异常。但必须在协程内捕获,不得跨协程捕获异常。
严重错误
多协程共用一个连接
与同步阻塞程序不同,协程是并发处理请求的,因此同一时间可能会有很多个请求在并行处理,一旦共用客户端连接,就会导致不同协程之间发生数据错乱。
使用类静态变量/全局变量保存上下文
多个协程是并发执行的,因此不能使用类静态变量 / 全局变量保存协程上下文内容。
使用局部变量是安全的,因为局部变量的值会自动保存在协程栈中,其他协程访问不到协程的局部变量。
正确方案:使用Context管理上下文
可以使用一个Context
类来管理协程上下文,在Context
类中,使用Coroutine::getUid
获取当前协程的ID,然后隔离不同协程之间的全局变量,协程退出时清理上下文数据
杂项
守护进程
就是后台运行的进程,详细来说就是脱离父进程的子进程,随后该子进程被1号进程接收