进程、协程
- 进程 > 线程 > 协程
- fpm框架使得整个程序是依托于nginx+cgi,和php脚本没太大的关系,在程序未被访问的时候担任的角色和普通静态网站差不多。但是基于swoole的http服务使得程序有了生命周期,整个程序的允许全部依赖于php脚本,类似springboot部署时候以java -jar启动时,开启一个新的进程。
- 传统的php-fpm框架是基于cgi开启多个fpm进程,比如设置了20个 那么这个程序只能同时拥有20个IO阻塞,其他的请求将会一直处于等待状态
协程实现了用同步的写法实现异步的代码,这就导致如果有大量的并发或者IO操作他会对并发的支持非常好,只要开启一个新的协程就行了
几个提示区
在一个协程内的代码是同步阻塞的,一个协程相对于另一个协程是异步的
- 协程的整块代码相对于别的代码是异步的
- swoole4+实现了一键协程化,也就是说没一次对于mysql、redis…的操作都是开启了一个协程
- 在基于swoole的协程框架中(hyperf、easyswoole等),每次的请求都是一个协程,业务方法内的代码也是协程化的,但是排除阻塞代码后其他代码都是同步执行的
- 如果是父子协程,子协程的代码对于父协程来说也是异步的(见下文)
协程客户端
其实就是对于mysql、redis的操作异步化了,每一次的增删改查都会去开启一个协程。大量的回调函数会让代码非常杂乱,所以4+版本支持一键协程化。只需要按往常写法就行
官方示例:
Co::set(['hook_flags' => SWOOLE_HOOK_TCP]);
$http = new Swoole\Http\Server("0.0.0.0", 9501);
$http->set(['enable_coroutine' => true]);
$http->on('request', function ($request, $response) {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);//此处产生协程调度,cpu切到下一个协程(下一个请求),不会阻塞进程
$redis->get('key');//此处产生协程调度,cpu切到下一个协程(下一个请求),不会阻塞进程
});
$http->start();
如官方所说,其实每次的IO操作,底层都会开启一个新的协程,让cpu来处理其他的协程。
父子协程
子协程的代码对于父协程来说是异步的
public function test3() {
Coroutine::create(function () {
for($i=0;$i<10;$i++){
Coroutine::create(function () use ($i) {
sleep(1);
echo $i . PHP_EOL;
});
}
echo 'parent';
});
echo 'hello';
return Coroutine::id();
}
以上代码方法内首先创建了一个协程,然后在协程内部新建了50个协程,但是最后输出的结果是所有子协程执行完成才输出的
输出结果:
parenthello0
9
8
7
6
5
4
3
2
1
传统框架对比
对比laravel、tp这种传统fpm框架,swoole类型的框架对于并发支持要好很多。但是如果线上使用还需要多踩坑,与传统框架比开发者有些书写习惯在swoole的框架中可能会不支持,比如die函数等。同时部署也会比以往框架麻烦点。以前只需要git拉下代码、更新composer然后配合nginx就可以访问了,swoole如果在线上部署要注意进程守护的问题,不能让进程宕掉,推荐使用docker方式部署。然后再通过nginx代理访问即可。