Skip to content

Instantly share code, notes, and snippets.

@fjarrett
Last active January 26, 2021 17:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fjarrett/4bc9f0b3c1a0a1877c2b2f382c00f88a to your computer and use it in GitHub Desktop.
Save fjarrett/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.
<?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;
}
<?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