三点说明
- swoole的协程coroutine使用借鉴与golang的goroutine
- coroutine的协程在主干结束之后让出,其它协程执行,而goroutine的主干结束之后,自动退出
- swoole的coroutine协程使用时,如果用死循环,主干一直在运行,资源不会让出,因此需要
co::sleep()
来主动让出资源给其它协程执行
Channel(管道)
php业务场景中,我们在多个进程之间的通信一般会通过redis内存缓存来达到效果 在协程间的通信,我们可以使用Channel来实现,在类比php多进程处理的时候,可以将Channel类比成redis的队列
/**
* Describe: 重要的事情多说几遍
* Created by PhpStorm.
* User: querying
* Date: 18-8-21
* Time: 上午11:34
*/
use Swoole\Channel;
Class Demo
{
public function startK()
{
// 任务数据管道
$chan = new Channel(1);
//管道用于检测是否需要跳出死循环
$pushStatusChan = new Channel(1);
$popStatusChan = new Channel(1);
$logStatusChan = new Channel(1);
go(function () use ($chan, $pushStatusChan) {
while (1) {
if ($pushStatusChan->pop() === 'break') {
break;
}
\Co::sleep(1);
$data = $this->getPushData();
if (!empty($data)) {
$chan->push($data);
var_dump("数据");
}
}
});
go(function () use ($chan, $popStatusChan) {
while (1) {
if ($popStatusChan->pop() === 'pop:break') {
break;
}
//主动让出
\Co::sleep(1);
$data = $chan->pop();
if (!empty($data)) {
var_dump("创建协程");
go(function () use ($data) {
$this->doTask($data);
});
var_dump("创建协程后");
}
}
});
go(function () use ($chan, $logStatusChan) {
while (1) {
if ($logStatusChan->pop() === 'break') {
break;
}
$coStatus = \Co::stats();
var_dump("协程数:{$coStatus['coroutine_num']}");
$this->memoryLog();
//每过5秒,记录进程占用内存
\Co::sleep(5);
}
});
go(function () use ($pushStatusChan, $popStatusChan, $logStatusChan) {
$now_hour = -1;
while (1) {
if ($now_hour !== date('H')) {
$now_hour = date('H');
}
//进程状态检测
$result = $this->processStatusCheck();
if (!$result) {
//这是友好的退出方案,如果需要及时退出,exit; / die;
//push协程跳出
$pushStatusChan->push('break');
//pop协程跳出
$popStatusChan->push("break");
//内存日志协程
$logStatusChan->push('break');
break;
}
\Co::sleep(3);
}
});
}
public function processStatusCheck()
{
// todo: 校验进程状态
return true;
}
public function memoryLog()
{
// todo: 记录当前进程使用内存
}
public function doTask($data)
{
// todo: 拿到管道数据然后根据数据处理进行业务处理
}
public function getPushData()
{
// todo: 获取需要放入管道的数据
return [
'test' => '666'
];
}
}