如何在PHP中并行执行内部函数?已尝试AMP及Swoole未果
在PHP中并行执行内部函数的可行方案
PHP里确实有多种方式实现函数的并行执行,针对你提到的AMP和Swoole使用失败的问题,下面附上经过验证的正确示例,同时提供其他可行方案:
1. 使用Swoole协程(推荐CLI/常驻进程场景)
Swoole的协程是轻量级并行方案,适合高性能场景。你之前没成功大概率是没正确处理协程间的结果同步,示例代码如下:
function a(){ return 1; } function b(){ return 2; } function c(){ return 3; } function d(){ return 4; } function E(){ $response = []; $chan = new Swoole\Channel(4); // 创建容量为4的通道,用于协程间传递结果 // 启动协程并行执行每个函数 go(function() use ($chan) { $chan->push(['key' => 'a', 'value' => a()]); }); go(function() use ($chan) { $chan->push(['key' => 'b', 'value' => b()]); }); go(function() use ($chan) { $chan->push(['key' => 'c', 'value' => c()]); }); go(function() use ($chan) { $chan->push(['key' => 'd', 'value' => d()]); }); // 从通道中取出所有结果 for ($i = 0; $i < 4; $i++) { $result = $chan->pop(); $response[$result['key']] = $result['value']; } $chan->close(); return $response; } // 执行并输出结果 var_dump(E());
通过go()创建独立协程执行每个函数,用Channel做协程间的通信,确保所有结果都被收集后再返回。
2. 使用AMP(异步并行编程框架)
AMP基于Promise实现异步并行,你之前失败可能是没正确使用Promise和await,正确示例如下:
首先确保已通过Composer安装AMP:composer require amphp/amp
require 'vendor/autoload.php'; use Amp\Promise; use function Amp\async; use function Amp\await; function a(){ return 1; } function b(){ return 2; } function c(){ return 3; } function d(){ return 4; } function E(){ // 用async包装每个函数,返回Promise对象 $promises = [ 'a' => async(fn() => a()), 'b' => async(fn() => b()), 'c' => async(fn() => c()), 'd' => async(fn() => d()), ]; // 等待所有Promise完成,批量获取结果 $response = await(Promise\all($promises)); return $response; } // 执行并输出结果 var_dump(E());
async()会把同步函数包装成异步Promise,Promise\all()等待所有Promise完成后返回对应结果数组,顺序和传入的Promise数组一致。
3. 使用PCNTL多进程(仅CLI环境)
如果你的场景是CLI脚本,可以用PCNTL扩展创建多进程并行执行,示例:
function a(){ return 1; } function b(){ return 2; } function c(){ return 3; } function d(){ return 4; } function E(){ $functions = [ 'a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd', ]; $pids = []; $response = []; $pipeHandles = []; foreach ($functions as $key => $func) { // 创建管道,用于子进程向父进程传递结果 $pipe = []; pipe($pipe); $pid = pcntl_fork(); if ($pid === -1) { die('创建进程失败'); } elseif ($pid === 0) { // 子进程:执行函数,将结果写入管道后退出 fclose($pipe[0]); $result = $func(); fwrite($pipe[1], json_encode(['key' => $key, 'value' => $result])); fclose($pipe[1]); exit(0); } else { // 父进程:保存进程ID和管道读端 $pids[] = $pid; $pipeHandles[$pid] = $pipe[0]; fclose($pipe[1]); } } // 等待所有子进程结束,读取结果 foreach ($pids as $pid) { pcntl_waitpid($pid, $status); $data = fread($pipeHandles[$pid], 1024); $result = json_decode($data, true); $response[$result['key']] = $result['value']; fclose($pipeHandles[$pid]); } return $response; } // 执行并输出结果 var_dump(E());
通过pcntl_fork()创建子进程,每个子进程执行一个函数,用管道传递结果给父进程,父进程等待所有子进程完成后收集结果。注意PCNTL扩展仅在CLI环境可用,web环境无法使用。
内容的提问来源于stack exchange,提问作者Buggy
相关产品推荐
相关产品推荐

