I want to create a thread using Fiber
(PHP 8.1) to send an email (email sending takes 10 seconds, so I decide to use a thread for it). And this is my code
<?php
$fiber = new Fiber(function () {
send_email();
});
$fiber->start();
exit(json_encode(['response' => 1]));
The result of send_email()
is not important but after start the fiber, fiber waits until send_email()
done then exit(json_encode(['response' => 1]));
happen !!!! I want it to exit immediately, but send email too !!!
what is the problem?
CodePudding user response:
According to https://www.php.net/manual/en/language.fibers.php the Fiber is interruptible, but there's no mentioned of it being full async or multithreading - it doesn't allow the main function to continue executing automatically...from my reading of it that would only occur if you paused the Fiber - and indeed that's the experience you've reported in your code.
PHP is single-threaded and also doesn't have any kind of proper task-based asynchronous programming model (unfortunately, that's now a major weakness compared to other server-side languages like nodeJS or C#).
https://php.watch/versions/8.1/fibers also says
It is important the concurrent execution does not mean simultaneous execution. The Fiber and the main execution flow does not happen at the same time. It is up to the main execution flow to start a Fiber, and when it starts, the Fiber is executed exclusively.
and
Fiber by itself does not allow simultaneous execution of multiple Fibers or the main thread and a Fiber.
...so I think perhaps you've misunderstood this feature and what it's capable of - it cannot help you to meet your requirement.
AFAIK with PHP it's not possible to do what you're attempting. A better solution might be to hand off the email sending to a separate process - e.g. a background task triggered by cron
. This is a fairly typical pattern: the PHP receives a request which requires it to send an email. It logs the request in a database table and then exits. The background task executes on a schedule, picks up any uncompleted tasks from the database table and runs them, then updates the table to say they're completed. That way it doesn't really matter much if the background task takes a bit longer, because it's not slowing down the website or the end users.