<?php
\Co\run(function () {
var_dump('coro run');
$chan = new \Co\Channel(1);
$res = $chan->pop();
var_dump("pop", $res);
});
var_dump("after coro");
What did you expect to see?
The "After coro" message should never be printed, because of $chan->pop() on empty channel should lead to an infinite waiting.
What did you see instead?
Channel gets automatically closed because coroutine scheduler has switched execution flow outside of the coroutine.
[2020-05-10 13:20:48 @20086.0] TRACE php_swoole_reactor_init(:254): init reactor
[2020-05-10 13:20:48 @20086.0] TRACE Context(:42): alloc stack: size=2097152, ptr=0x7fa38cc88010
[2020-05-10 13:20:48 @20086.0] TRACE main_func(:685): Create coro id: 1, origin cid: -1, coro total count: 1, heap size: 1285832
string(8) "coro run"
[2020-05-10 13:20:48 @20086.0] TRACE yield(:52): consumer cid=1
[2020-05-10 13:20:48 @20086.0] TRACE on_yield(:544): php_coro_yield from cid=1 to cid=-1
string(10) "after coro"
[2020-05-10 13:20:48 @20086.0] TRACE close(:159): channel closed
[2020-05-10 13:20:48 @20086.0] TRACE pop_coroutine(:146): resume consumer cid=1
[2020-05-10 13:20:48 @20086.0] TRACE on_resume(:556): php_coro_resume from cid=-1 to cid=1
string(3) "pop"
bool(false)
[2020-05-10 13:20:48 @20086.0] TRACE on_close(:589): coro close cid=1 and resume to -1, 0 remained. usage size: 1276688. malloc size: 2097152
[2020-05-10 13:20:48 @20086.0] TRACE close(:94): coroutine#1 stack memory use less than 65536 bytes
[2020-05-10 13:20:48 @20086.0] TRACE ~Context(:74): free stack: ptr=0x7fa38cc88010
php --ri swoole)?swoole
Swoole => enabled
Author => Swoole Team <[email protected]>
Version => 4.5.0
Built => May 10 2020 06:50:53
coroutine => enabled
debug => enabled
trace_log => enabled
epoll => enabled
eventfd => enabled
signalfd => enabled
cpu_affinity => enabled
spinlock => enabled
rwlock => enabled
openssl => OpenSSL 1.1.1f 31 Mar 2020
http2 => enabled
pcre => enabled
zlib => 1.2.11
brotli => E16777223/D16777223
mutex_timedlock => enabled
pthread_barrier => enabled
futex => enabled
async_redis => enabled
Directive => Local Value => Master Value
swoole.enable_coroutine => On => On
swoole.enable_library => On => On
swoole.enable_preemptive_scheduler => Off => Off
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.unixsock_buffer_size => 8388608 => 8388608
@codercms
It's one of Swoole's designs. The Swoole kernel does not make the state of the channel an exit condition for the event scheduler. in Swoole 4.5, you can customize the exit condition for the event scheduler:
<?php
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
use function Swoole\Coroutine\run;
run(function () {
var_dump('coro run');
$chan = new Channel(1);
Coroutine::set([
'exit_condition' => function () use ($chan) {
return $chan->stats()['consumer_num'] === 0;
}
]);
$res = $chan->pop();
var_dump("pop", $res);
});
var_dump("after coro");
@huanghantao got it, thanks for your note
Most helpful comment
@codercms
It's one of Swoole's designs. The Swoole kernel does not make the state of the channel an exit condition for the event scheduler. in Swoole 4.5, you can customize the exit condition for the event scheduler: