How to check if script/context is being executed inside Swoole?
What is correct approach from inside a script to check, if it being executed in Swoole Co\Run context? Basically, I am trying to make a library-function of sleep, which I want to be called by Swoole/non-Swoole scripts:
public function sleep($seconds){
if (method_exists('\\Swoole\\Coroutine\\System','sleep') && I_AM_BEING_EXECUTED_IN_SWOOLE_COROUTINE () )
\Swoole\Coroutine\System::sleep($seconds);
else sleep($seconds);
}
so, I want a real alternative instead of I_AM_BEING_EXECUTED_IN_SWOOLE_COROUTINE () function.
Simply use the sleep function provided by php. After Co\run is started, it will automatically replace the synchronously blocked sleep with the asynchronous sleep function of coroutine
thanks ! btw, so just anyway (for other purposes) is there any way to find out if current script is being executed inside coroutine or not? (you can close the issue after answer) . tnx
code
<?php
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;
run(function() {
echo "sleep begin\n";
sleep(1);
echo "sleep end\n";
});
strace
strace php sleep.php
...
epoll_create(512) = 3
mmap(NULL, 2101248, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0e20a69000
write(1, "sleep begin\n", 12sleep begin
) = 12
epoll_wait(3, [], 4096, 1000) = 0
madvise(0x55b9d84d7000, 4096, MADV_DONTNEED) = 0
brk(0x55b9d84ea000) = 0x55b9d84ea000
epoll_wait(3, [], 4096, 1) = 0
write(1, "sleep end\n", 10sleep end
) = 10
munmap(0x7f0e20a69000, 2101248) = 0
close(3) = 0
close(0) = 0
munmap(0x7f0e20eec000, 916544) = 0
munmap(0x7f0e214f1000, 392272) = 0
munmap(0x7f0e20ebc000, 196608) = 0
munmap(0x7f0e22600000, 2097152) = 0
munmap(0x7f0e20e6b000, 331776) = 0
munmap(0x7f0e252f2000, 135168) = 0
exit_group(0) = ?
+++ exited with 0 +++
@ttodua Use Swoole\Coroutine::getCid(), if return -1, that means it is not in coroutine
Yeah,that is !!! thnxx
However, I have to recommend you to make a critical note with regard to sleep.
The reason I've mentioned the fail-safe 'sleep' function (in the first post), is that is still needs to be determined whether the script is being run within coroutine or not. Do you want to know the main reason, why?
because, the script will lead to unexpected results.
For example, when you execute sleep(0.2) it will misbehave , as native sleep only accepts integer (thus, the float number will be rounded to integer). you can try the same code within native php and within coroutine:
echo microtime(true)."\r\n";
sleep(0.99);
echo microtime(true)."\r\n";
and you will get different results (native php will round that to 0 seconds). So, it matters where sleep is executed, to avoid unexpected errors/results.
so, for that reason, i've created this fail-safe function:
public function sleep($seconds){
if ( method_exists('\\Swoole\\Coroutine\\System','sleep') )
\Swoole\Coroutine\System::sleep($seconds);
else {
if ( filter_var($seconds, FILTER_VALIDATE_INT) !== false)
sleep($seconds);
else
usleep($seconds/1000000);
}
}
just my 2 cents.
I might advise to create usleep version in swoole to match the well-known behavior of native usleep thus, it will lead people to less errors, instead of relying on sleep, or make some notes on official DOCS, that Swoole's sleep is unline native sleep because it accepts decimals too, not only integer.
The example you provided looks incorrect for me...
sleep(1) is equal to usleep(1 * 1000 * 1000), so your code should be usleep($seconds * 1000000).
And you need not to check it, on Swoole coroutine, usleep() will be replaced by Swoole automatically. It means, when you using usleep in Swoole coroutine, usleep(1000) is equal to Swoole\Coroutine\System::sleep(0.001).
@twose Uh-oh, yes, there should be multiplier, not divisor , of 1000000. my stupid mistake :)
But I meant about Sleep's misbehavior when called within or outside coroutine, they provide different results.
In Swoole, we recommand you to put all of your code in coroutine, do not do anything outside of coroutine, Co\run() is like main() in C.
@ttodua Use
Swoole\Coroutine::getCid(), if return -1, that means it is not in coroutine
May I ask? It has a bug.
I see that typically, it should work - tested with this funcion.
var_dump("cid (PHP):".\Swoole\Coroutine::getCid());
var_dump("Pcid (PHP):".\Swoole\Coroutine::getPcid());
\Swoole\Coroutine\run( function(){
var_dump("cid (RUN):".\Swoole\Coroutine::getCid());
var_dump("Pcid (RUN):".\Swoole\Coroutine::getPcid());
go(
function(){
var_dump("cid (RUN\GO):".\Swoole\Coroutine::getCid());
var_dump("Pcid (RUN\GO):".\Swoole\Coroutine::getPcid());
}
);
} );
exit("");
and result was:
"cid (PHP):-1"
"Pcid (PHP):"
"cid (RUN):3"
"Pcid (RUN):-1"
"cid (RUN\GO):4"
"Pcid (RUN\GO):3"
however, something strange happened though. I have function wrapper, exactly like this:
if ( \Swoole\Coroutine::getCid()==-1 )
{
\Swoole\Coroutine\run(function() {
go( ... );
});
}
// scheduler started, no need to "run", instead directly go:
else{
go( ... );
}
However, I still found some errors in logs : PHP Warning: Swoole\Coroutine\Scheduler::start(): eventLoop has already been created. unable to start Swoole\Coroutine\Scheduler in (like mentioned here ). Are you sure that given method is guaranteed way to check that we are in coroutine (scheduler already started) ? Is there any better way to check it?
My opinion, just use go() everywhere. And main() I usually use if(!debug_backtrace()){ ... } as main wrapper like Python if __name__ == "__main__"
My opinion, just use
go()everywhere. Andmain()I usually useif(!debug_backtrace()){ ... }as main wrapper like Pythonif __name__ == "__main__"
Co\run() only can be used at the top of coroutine context, and go() will automatically recognize it. To check if script is being executed inside coroutine, Co::getCid() is a right way.