Last active
January 26, 2021 17:38
-
-
Save frankiejarrett/4bc9f0b3c1a0a1877c2b2f382c00f88a to your computer and use it in GitHub Desktop.
Apply a user supplied function to every member of an array, in parallel. Similar to PHP's array_walk(), except the input array isn't passed by reference and the callbacks are ran asynchronously. The technique is highly portable and requires only PHP 5.4 and the PCNTL extension.
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 | |
/** | |
* Apply a user supplied function to every member of an array, in parallel | |
* | |
* Similar to PHP's array_walk(), except the input array isn't passed by | |
* reference and the callbacks are ran asynchronously. The technique is highly | |
* portable and requires only PHP 5.4 and the PCNTL extension. | |
* | |
* The most obvious limitation is that we can't pass the input array by | |
* reference to modify it, this is because child processes have no awareness of | |
* the parent and therefore can't pass data back to the original process. | |
* | |
* @author Frankie Jarrett | |
* | |
* @param array $array The input array. | |
* @param callable $callback Takes on two parameters, the array parameter's | |
* value being the first, and the key second. | |
* @param int $max_children Limit the maximum number of children (forks) | |
* that can run in parallel. Defaults to 20. | |
* | |
* @return true | |
*/ | |
function async_array_walk(array $array, callable $callback, $max_children = 20) | |
{ | |
$pids = []; | |
foreach ($array as $key => $value) { | |
// Sync (slow). | |
if (! function_exists('pcntl_fork')) { | |
$callback($value, $key); | |
} | |
// Async (fast). | |
if (count($pids) >= (int) $max_children) { | |
$pid = pcntl_waitpid(-1, $status); | |
unset($pids[ $pid ]); | |
} | |
$pid = pcntl_fork(); | |
// Parent process. | |
if ($pid > 0) { | |
$pids[] = $pid; | |
} | |
// Child process (fork). | |
if (0 === $pid) { | |
$callback($value, $key); | |
exit; | |
} | |
} | |
// Wait for all forks to finish. | |
foreach ($pids as $pid) { | |
pcntl_waitpid($pid, $status); | |
} | |
return true; | |
} |
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 | |
$fruits = [ | |
'apples.txt' => 'I like apples', | |
'bananas.txt' => 'I like bananas', | |
'oranges.txt' => 'I like oranges', | |
]; | |
async_array_walk($fruits, function ($value, $key) { | |
sleep(2); | |
file_put_contents($key, $value); | |
}); | |
// All 3 files will be written in 2 seconds, not 6 seconds. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment