note 127282 added to language.fibers
| From: | AliMadadi at main dot php dot net | Date: | Thu, 14 Jul 2022 10:17:58 +0000 |
| Subject: | note 127282 added to language.fibers | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-219007@lists.php.net to get a copy of this message | ||
Here is a simple scheduler and thread pool that implements multithreading using fibers and tick
functions in PHP 8.1 and returns the return value of each function in the pool in an array at the
end.
Note that due to some bugs, you need to register a new tick function for each "thread".
Remember to unregister all of them at the end.
The link bellow is the discussion on a bug that is going on right now (At the time of writing this).
Note that based on the discussion, the ability to call Fiber::suspend() inside tick function may
become forbidden in PHP 8.2+. But if the bug gets fixed, you can move register_tick_function() line
to the top of the class, and this simple multithreading class in pure PHP code will work like a
charm.
https://github.com/php/php-src/issues/8960
<?php
declare(ticks=1);
class Thread {
protected static $names = [];
protected static $fibers = [];
protected static $params = [];
public static function register(string|int $name, callable $callback, array $params)
{
self::$names[] = $name;
self::$fibers[] = new Fiber($callback);
self::$params[] = $params;
}
public static function run() {
$output = [];
while (self::$fibers) {
foreach (self::$fibers as $i => $fiber) {
try {
if (!$fiber->isStarted()) {
// Register a new tick function for scheduling this fiber
register_tick_function('Thread::scheduler');
$fiber->start(...self::$params[$i]);
} elseif ($fiber->isTerminated()) {
$output[self::$names[$i]] = $fiber->getReturn();
unset(self::$fibers[$i]);
} elseif ($fiber->isSuspended()) {
$fiber->resume();
}
} catch (Throwable $e) {
$output[self::$names[$i]] = $e;
}
}
}
return $output;
}
public static function scheduler () {
if(Fiber::getCurrent() === null) {
return;
}
// running Fiber::suspend() in this if condition will prevent an infinite loop!
if(count(self::$fibers) > 1)
{
Fiber::suspend();
}
}
}
?>
And here is an example code on how to use above Thread class:
<?php
// defining a non-blocking thread, so multiple calls will run in concurrent mode using above Thread
class.
function thread (string $print, int $loop)
{
$i = $loop;
while ($i--){
echo $print;
}
return "Thread '{$print}' finished after printing '{$print}' for {$loop}
times!";
}
// registering 6 Threads (A, B, C, D, E, and F)
foreach(range('A', 'F') as $c) {
Thread::register($c, 'thread', [$c, rand(5, 20)]);
}
// run threads and wait until execution finishes
$outputs = Thread::run();
// print outputs
echo PHP_EOL, '-------------- RETURN VALUES --------------', PHP_EOL;
print_r($outputs);
?>
The output will be something like this (but probably different):
ABCDEFABCDEFABCDEFABCDEFABCDEFABCEFABFABFABEBEFBEFEFEFAABEABEBEFBEFFAAAAAA
-------------- RETURN VALUES --------------
Array
(
[D] => Thread 'D' finished after printing 'D' for 5 times!
[C] => Thread 'C' finished after printing 'C' for 6 times!
[E] => Thread 'E' finished after printing 'E' for 15 times!
[B] => Thread 'B' finished after printing 'B' for 15 times!
[F] => Thread 'F' finished after printing 'F' for 15 times!
[A] => Thread 'A' finished after printing 'A' for 18 times!
)
----
Server IP: 45.112.84.4
Probable Submitter: 80.90.5.135 (proxied: 2.187.180.130)
----
Manual Page -- https://php.net/manual/en/language.fibers.php
Edit -- https://main.php.net/note/edit/127282
Del: integrated -- https://main.php.net/note/delete/127282/integrated
Del: useless -- https://main.php.net/note/delete/127282/useless
Del: bad code -- https://main.php.net/note/delete/127282/bad+code
Del: spam -- https://main.php.net/note/delete/127282/spam
Del: non-english -- https://main.php.net/note/delete/127282/non-english
Del: in docs -- https://main.php.net/note/delete/127282/in+docs
Del: other reasons-- https://main.php.net/note/delete/127282
Reject -- https://main.php.net/note/reject/127282
Search -- https://main.php.net/manage/user-notes.php