Closed dongzitai closed 3 years ago
你的enable_coroutine
是关闭了事件回调中的协程。而你waitPid是创建了一个新的协程,所以出现了这个报错和非协程环境下无关
当Swoole
内核清理Reactor
(你可以理解为事件管理器)的时候会回调一个死锁检测的函数,如果当前还有协程没有退出(比如你这里的挂起,调用waitPid导致的协程挂起),会报这个deadlock
的错误。
这里有两个关键的地方:
Reactor
。目前,当调用Process::start
这个函数fork
子进程的时候,会在子进程清理从父进程“继承”下来的Reactor
。所以,你这段程序等价于:
<?php
use Swoole\Coroutine;
Swoole\Coroutine::create(function () {
Coroutine::yield();
});
$process = new \Swoole\Process(function (\Swoole\Process $process) {
$i = 0;
while (true) {
sleep(1);
echo '进程号: ' . $process->pid .' 计数: ' . ++$i . PHP_EOL;
}
});
$process->start();
$process->wait();
当
Swoole
内核清理Reactor
(你可以理解为事件管理器)的时候会回调一个死锁检测的函数,如果当前还有协程没有退出(比如你这里的挂起,调用waitPid导致的协程挂起),会报这个deadlock
的错误。 这里有两个关键的地方:
- 你这段程序什么时候会去清理
Reactor
。目前,当调用Process::start
这个函数fork
子进程的时候,会在子进程清理从父进程“继承”下来的Reactor
。- 什么时候会去注册这个死锁检测函数。目前,当创建一个协程的时候,会注册检测函数。
所以,你这段程序等价于:
<?php use Swoole\Coroutine; Swoole\Coroutine::create(function () { Coroutine::yield(); }); $process = new \Swoole\Process(function (\Swoole\Process $process) { $i = 0; while (true) { sleep(1); echo '进程号: ' . $process->pid .' 计数: ' . ++$i . PHP_EOL; } }); $process->start(); $process->wait();
基于我上文描述的场景,在创建完子进程后,新建的子进程会继承挂起的协程吗?在使用Coroutine::list()
+Coroutine::getBackTrace($cid)
统计新建的子进程中的协程信息时,发现有父进程挂起协程信息。
Swoole\Coroutine::create(function () use ($process) {
$status = \Swoole\Coroutine\System::waitPid($process->pid);
var_dump($status);
});
是的,比如说父进程里面的协程个数,在子进程里面也会继承下来。
是的,比如说父进程里面的协程个数,在子进程里面也会继承下来。
只是协程的数量和堆栈信息吗?运行的协程应该不会被继承吧?我的意思是父子进程中同时运行两个一样的协程?
怎么说呢,这是一个很邪恶的问题了,你可以跑这个脚本自己体会下:
<?php
use Swoole\Coroutine;
$cid1 = Swoole\Coroutine::create(function () {
Coroutine::yield();
var_dump("process " . posix_getpid() . "coroutine ". Coroutine::getCid());
});
$process = new \Swoole\Process(function (\Swoole\Process $process) use ($cid1) {
Coroutine::resume($cid1);
});
$process->start();
Coroutine::resume($cid1);
$process->wait();
你可以在子进程和父进程resume
挂起的协程,但是,它们理论上来说已经不是同一个了。这你得从内存的角度去理解协程。
怎么说呢,这是一个很邪恶的问题了,你可以跑这个脚本自己体会下:
<?php use Swoole\Coroutine; $cid1 = Swoole\Coroutine::create(function () { Coroutine::yield(); var_dump("process " . posix_getpid() . "coroutine ". Coroutine::getCid()); }); $process = new \Swoole\Process(function (\Swoole\Process $process) use ($cid1) { Coroutine::resume($cid1); }); $process->start(); Coroutine::resume($cid1); $process->wait();
你可以在子进程和父进程
resume
挂起的协程,但是,它们理论上来说已经不是同一个了。这你得从内存的角度去理解协程。
那就是像我刚才那个场景子进程中继承过来的挂起协程\Swoole\Coroutine\System::waitPid($process->pid);
永远都不会释放啦?。。
这里存在带协程 fork 的问题,如果全部是同步阻塞的,建议直接使用 Process::wait()
这里存在带协程 fork 的问题,如果全部是同步阻塞的,建议直接使用
Process::wait()
如果在worker进程中去管理进程(使用\Swoole\Process
),经过测试不使用Process::wait()
或者\Swoole\Coroutine\System::waitPid
这个API,子进程并没有蜕变为僵尸进程,是因为worker持续运行不退出的原因,还是其他有其他原因,在worker
运行的上下文,不使用Process::wait()
或者\Swoole\Coroutine\System::waitPid
这个API,会存在问题吗?
@dongzitai 你可以加下我微信85464277沟通
Please answer these questions before submitting your issue. Thanks!
$map = [];
$serv = new \Swoole\Http\Server("127.0.0.1", 9502, SWOOLE_BASE, SWOOLE_SOCK_TCP);
$serv->set(array( 'worker_num' => 1, 'daemonize' => false, 'backlog' => 128, 'enable_coroutine' => false ));
$serv->on('Start', 'start'); $serv->on('WorkerStart', 'workerStart'); $serv->on('request', 'request'); $serv->start();
function start(Swoole\Server $server) { echo 'server 启动' . PHP_EOL; }
function workerStart(Swoole\Server $server, int $workerId) { echo 'worker启动' . $workerId . PHP_EOL; global $map; for ($i = 0; $i < 2; $i++) { $process = new \Swoole\Process(function (\Swoole\Process $process) { $i = 0; while (true) { sleep(1); echo '进程号: ' . $process->pid .' 计数: ' . ++$i . PHP_EOL; } }); $process->start();
}
function request($request, $response) { $response->end("
Hello Swoole. #".rand(1000, 9999)."
"); }=================================================================== [FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!
[Coroutine-1]
0 Swoole\Coroutine\System::waitPid() called at [/Users/dongzt/swoole-pro/amqp-test/dongzt/swoole-http-server.php:44]
php --ri swoole
)?uname -a
&php -v
&gcc -v
) ?PHP 7.4.19 (cli) (built: May 13 2021 06:28:47) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Yasd v0.3.9-alpha, Our Copyright, by codinghuang with Zend OPcache v7.4.19, Copyright (c), by Zend Technologies
Apple clang version 12.0.0 (clang-1200.0.32.29) Target: x86_64-apple-darwin20.3.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin