Last active
January 14, 2024 21:18
-
-
Save nggit/4419705331f008d0c00b329c48906fad to your computer and use it in GitHub Desktop.
A simple event loop with Fibers (PHP 8 >= 8.1.0)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// a simple event loop with Fibers (PHP 8 >= 8.1.0) | |
// in a style slightly inspired by Python's asyncio | |
// this will not immediately increase the throughput of your code | |
// since the functions are still executed sequentially in the event loop | |
// unless you can combine it with a non-blocking stream/socket | |
// to create the impression of io parallelism | |
class Loop | |
{ | |
// defered tasks | |
public static $tasks = []; | |
public static function createTask($coro) | |
{ | |
$fiber = new Fiber(function () use ($coro) { | |
// defer | |
Fiber::suspend(); | |
return $coro(); | |
}); | |
$fiber->start(); | |
self::$tasks[] = $fiber; | |
return $fiber; | |
} | |
public static function await($fiber) | |
{ | |
while (!$fiber->isTerminated()) { | |
// yield the current task until an awaited task is done | |
Fiber::suspend(); | |
} | |
return $fiber->getReturn(); | |
} | |
public static function run($coro = null) | |
{ | |
// optionally create a main task | |
if (is_callable($coro)) { | |
self::createTask($coro); | |
} | |
// event loop | |
while (self::$tasks) { | |
$fiber = array_shift(self::$tasks); | |
if ($fiber->isSuspended() && !$fiber->isTerminated()) { | |
// execute defered tasks | |
$fiber->resume(); | |
} | |
if (!$fiber->isTerminated()) { | |
// reschedule | |
self::$tasks[] = $fiber; | |
} | |
} | |
} | |
} | |
// coroutines | |
$coro1 = function () { | |
return 'Task 1' . PHP_EOL; | |
}; | |
$coro2 = function () { | |
return 'Task 2' . PHP_EOL; | |
}; | |
// tasks | |
$task1 = Loop::createTask($coro1); | |
$task2 = Loop::createTask($coro2); | |
$main = function () use ($task1, $task2) { | |
echo Loop::await($task2); | |
echo Loop::await($task1); | |
echo 'Main task', PHP_EOL; | |
}; | |
echo 'Before event loop', PHP_EOL; | |
var_dump(Loop::$tasks); | |
// run the event loop | |
Loop::run($main); | |
echo 'After event loop', PHP_EOL; | |
var_dump(Loop::$tasks); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment