-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Process] Add support for Fiber #43678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 7.3
Are you sure you want to change the base?
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Glad to see that you consider using Fibers! 🤗
My point is that it could be interesting to define a contract about "how to use safely a SF Process in a Fiber". I have no particular idea about this, I'm not sure if Symfony needs a complete async tools set, but I'm just wondering if this Anyway, this PR has my full attention 😉👍 |
Thanks a lot for your feedback
The process will last, but it's exactly the same as when you write the follow code
So IMHO, nothing has to be done here
What would be the use case to resume it with
Indeed, I was not sure about the use case, but actually, it eases the async handling of process.
I totally agree with that 👍🏼, and more generally in Symfony
Yes, it can. I said that, because we keeps reading issue where people do really strange things :) I guess it's how OSS works :) |
👍
Since it's possible, we can expect that someone will try 😅.
😅😉 |
What's the status here? @lyrixx? |
I think there is consensus yet on how to add fibrer support in Symfony. Let's close it But if someone want it, we could also merge it. |
mhh wait why is this not merged? |
Wep, too bad. People are not ready for that! And we need that in castor cc @joelwurtz |
@lyrixx Not sure how you came to that conclusion as you were the one closing this PR. |
Let's re-open the PR 👍🏼 (rebased, and updated) |
784f22c
to
1c5b2ee
Compare
$startedAt = microtime(true); | ||
$fiber->suspend(); | ||
$sleepFor = (int) (1000 - (microtime(true) - $startedAt) * 1000000); | ||
if (0 < $sleepFor) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(same below)
$startedAt = microtime(true); | |
$fiber->suspend(); | |
$sleepFor = (int) (1000 - (microtime(true) - $startedAt) * 1000000); | |
if (0 < $sleepFor) { | |
$suspendedAt = microtime(true); | |
$fiber->suspend(); | |
if (0 < $sleepFor = (int) (1000 - (microtime(true) - $suspendedAt) * 1000000)) { |
But I would also make readPipe return true/false whether the process did yield some activity or not. This way, we won't force a sleep while there are things to do.
After playing a bit with the process and fiber, i think there is no need to add fiber support in this class, the only things the process class need would be getter for the Here is an example on how it may work (i use closure binding to get the streams) : require 'vendor/autoload.php';
$pid = null;
$running = true;
// listen for sigchld
pcntl_signal(SIGCHLD, function ($signo, $data) use (&$pid, &$running) {
if ($pid === $data['pid']) {
$running = false;
}
});
pcntl_async_signals(true);
$fiber = new Fiber(function () {
$process = \Symfony\Component\Process\Process::fromShellCommandline('echo -n "test"; echo -n "bar" 1>&2 ; sleep 2');
// bind a function to get the output stream
$getStdout = Closure::bind(function () {
return $this->stdout;
}, $process, $process);
$getStderr = Closure::bind(function () {
return $this->stderr;
}, $process, $process);
$process->start();
$stdout = $getStdout();
$stderr = $getStderr();
stream_set_blocking($stdout, 0);
stream_set_blocking($stderr, 0);
while ($process->isRunning()) {
$action = \Fiber::suspend([$stdout, $stderr]);
if ($action === 'stdout') {
$content = $process->getIncrementalOutput();
if ($content !== '') {
var_dump('stdout : ' . $content);
}
}
if ($action === 'stderr') {
$content = $process->getIncrementalErrorOutput();
if ($content !== '') {
var_dump('stderr : ' . $content);
}
}
}
return $process->getExitCode();
});
[$stdout, $stderr] = $fiber->start();
$streams = [$stdout, $stderr];
while (!$fiber->isTerminated()) {
$write = null;
$except = null;
$read = $streams;
$modified = stream_select($read, $write, $except, 0, 100_000);
if ($modified === false) {
break;
}
if ($modified > 0) {
foreach ($read as $stream) {
if ($fiber->isTerminated()) {
break;
}
if ($stream === $stdout) {
$fiber->resume('stdout');
}
if ($stream === $stderr) {
$fiber->resume('stderr');
}
}
}
}
var_dump('exit code : ' . $fiber->getReturn()); There may be some adjustement to do in the process class, but checking for fibers may not be needed IMHO Also this totally remove sleep inside the process, (it may sleep but it depends only on the event loop implementation) Exposing those streams make it be compatible with Revolt also, and i believe it would be better to provider a helper around the |
Didn't see this was in the Part of this example can be reuse, like instead of doing a |
@@ -429,12 +429,31 @@ public function wait(?callable $callback = null): int | ||
do { | ||
$this->checkTimeout(); | ||
$running = $this->isRunning() && ('\\' === \DIRECTORY_SEPARATOR || $this->processPipes->areOpen()); | ||
$this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running); | ||
if ($fiber = \Fiber::getCurrent()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe there should be an additional flag to enable this support otherwise it would be a bc break for people already using this method in a Fiber
$fiber->suspend(); | ||
$sleepFor = (int) (1000 - (microtime(true) - $startedAt) * 1000000); | ||
if (0 < $sleepFor) { | ||
usleep($sleepFor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe it could use stream_select on the pipes instead of usleep ? so it would directly read / write if there is something to do instead of sleeping ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we do use stream_select already so I guess we added this to address a situation where stream_select doesn't apply. git blame could help remember :)
Is it still relevant? |
Example:
(Note: The loop is very naive, but it's for demo purpose)
process-fiber.mp4