什么是进程?
进程就是应用程序的启动实例。独立的文件资源,数据资源,内存空间。
什么是线程?
线程属于进程,是程序的执行者。一个进程至少包含一个主线程,也可以有更多的子线程。线程有两种调度策略,一是:分时调度,二是:抢占式调度。
什么是协程?
协程是轻量级线程,协程也是属于线程,协程是在线程里执行的。协程的调度是用户手动切换的,所以又叫用户空间线程。协程的创建、切换、挂起、销毁全部为内存操作,消耗是非常低的。协程的调度策略是:协作式调度。
Swoole 协程的原理
Swoole4 由于是单线程多进程的,同一时间同一个进程只会有一个协程在运行。
Swoole server 接收数据在 worker 进程触发 onReceive 回调,产生一个携程。Swoole 为每个请求创建对应携程。协程中也能创建子协程。
协程在底层实现上是单线程的,因此同一时间只有一个协程在工作,协程的执行是串行的。
因此多任务多协程执行时,一个协程正在运行时,其他协程会停止工作。当前协程执行阻塞 IO 操作时会挂起,底层调度器会进入事件循环。当有 IO 完成事件时,底层调度器恢复事件对应的协程的执行。。所以协程不存在 IO 耗时,非常适合高并发 IO 场景。(如下图)
Swoole 的协程执行流程
协程没有 IO 等待 正常执行 PHP 代码,不会产生执行流程切换
协程遇到 IO 等待 立即将控制权切,待 IO 完成后,重新将执行流切回原来协程切出的点
协程并行协程依次执行,同上一个逻辑
协程嵌套执行流程由外向内逐层进入,直到发生 IO,然后切到外层协程,父协程不会等待子协程结束
CODE
协程HTTP_SERVER
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?php go(function () { $server = new Co\Http\Server("0.0.0.0", 8881); $server->handle('/', function ($request, $response) { $response->end("<h1>Index</h1>"); }); $server->handle('/test', function ($request, $response) { $response->end("<h1>Test</h1>"); }); $server->handle('/stop', function ($request, $response) use ($server) { $response->end("<h1>Stop</h1>"); $server->shutdown(); }); $server->handle('/websocket', function ($request, $ws) { $ws->upgrade(); while (true) { $frame = $ws->recv(); if ($frame === false) { echo "error : " . swoole_last_error() . "\n"; break; } else if ($frame == '') { break; } else { $ws->push("Hello {$frame->data}!"); $ws->push("How are you, {$frame->data}?"); } } });
$server->start(); });
|
协程原生PHPredis客户端
1 2 3 4 5 6 7
| <?php Swoole\Runtime::enableCoroutine(true); go(function (){ $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $val = $redis->get('key'); });
|
协程文件IO操作
1 2 3 4 5 6 7 8
| <?php Swoole\Runtime::enableCoroutine(true); go(function () { $fp = fopen("test.log", "a+"); fwrite($fp, str_repeat('A', 2048)); fwrite($fp, str_repeat('B', 2048)); fclose($fp); });
|