php实现异步操作
使用pcntl_fork创建子进程
在PHP中可以通过pcntl_fork创建子进程实现异步操作。父进程继续执行主逻辑,子进程处理耗时任务。需确保PHP已安装pcntl扩展,且仅在CLI模式下可用。
$pid = pcntl_fork();
if ($pid == -1) {
die('无法创建子进程');
} elseif ($pid) {
// 父进程继续执行
echo "父进程ID: " . getmypid() . "\n";
} else {
// 子进程处理异步任务
sleep(2);
echo "子进程ID: " . getmypid() . " 完成任务\n";
exit; // 子进程必须退出
}
通过curl_multi实现并发HTTP请求
利用curl_multi_init可同时发起多个HTTP请求,适用于需要并行调用外部API的场景。
$urls = ['http://api1.example.com', 'http://api2.example.com'];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$handles[] = $ch;
}
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
foreach ($handles as $ch) {
echo curl_multi_getcontent($ch) . "\n";
curl_multi_remove_handle($mh, $ch);
}
curl_multi_close($mh);
使用消息队列(如Redis)
通过Redis的LPUSH/BRPOP实现任务队列,生产者将任务存入队列,消费者异步处理。
// 生产者代码
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->lPush('task_queue', json_encode(['task' => 'async_job']));
// 消费者代码(常驻进程)
while (true) {
$task = $redis->brPop('task_queue', 0);
$data = json_decode($task[1], true);
// 处理任务逻辑
echo "处理任务: " . $data['task'] . "\n";
}
使用Gearman任务分发系统
Gearman专门用于分布式任务分发,需安装Gearman服务端及PHP扩展。
// Worker端注册任务
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('async_task', function($job) {
return strtoupper($job->workload());
});
while ($worker->work());
// Client端提交任务
$client = new GearmanClient();
$client->addServer();
$client->doBackground('async_task', 'data_to_process');
结合ignore_user_abort实现后台运行
通过设置ignore_user_abort让脚本在客户端断开后继续执行,适用于HTTP请求触发的异步任务。
ignore_user_abort(true);
set_time_limit(0);
echo "请求已接收,处理将继续在后台运行\n";
fastcgi_finish_request(); // 仅适用于PHP-FPM
// 模拟耗时任务
sleep(10);
file_put_contents('async.log', '任务完成');
使用Swoole协程框架
Swoole提供了协程、定时器、异步TCP/UDP等能力,适合高性能异步场景。
Swoole\Runtime::enableCoroutine();
go(function () {
$client = new Swoole\Coroutine\Http\Client('example.com', 80);
$client->get('/api');
echo $client->body;
$client->close();
});
注意事项
pcntl_fork和curl_multi适用于CLI模式,HTTP请求中需改用其他方案。- 消息队列需确保消费者进程常驻,可通过Supervisor管理进程。
- 异步操作涉及资源竞争时(如文件、数据库),需添加锁机制。







