什么是进程?

进程就是应用程序的启动实例。独立的文件资源,数据资源,内存空间。

什么是线程?

线程属于进程,是程序的执行者。一个进程至少包含一个主线程,也可以有更多的子线程。线程有两种调度策略,一是:分时调度,二是:抢占式调度。

什么是协程?

协程是轻量级线程,协程也是属于线程,协程是在线程里执行的。协程的调度是用户手动切换的,所以又叫用户空间线程。协程的创建、切换、挂起、销毁全部为内存操作,消耗是非常低的。协程的调度策略是:协作式调度。

Swoole 协程的原理

  1. Swoole4 由于是单线程多进程的,同一时间同一个进程只会有一个协程在运行。

  2. Swoole server 接收数据在 worker 进程触发 onReceive 回调,产生一个携程。Swoole 为每个请求创建对应携程。协程中也能创建子协程。

  3. 协程在底层实现上是单线程的,因此同一时间只有一个协程在工作,协程的执行是串行的。

  4. 因此多任务多协程执行时,一个协程正在运行时,其他协程会停止工作。当前协程执行阻塞 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();
});
//websocket 支持
$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);
});

 评论


本站使用 Material X 作为主题 , 总访问量为 次 。
隐藏