本文目录导读:

在 PHP 项目中实现异步处理有多种方式,每种方式都有其适用场景,以下是主要的实现方案:
消息队列(最常用)
RabbitMQ
// 生产者
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('task_queue', false, true, false, false);
$msg = new AMQPMessage('Hello World!', ['delivery_mode' => 2]);
$channel->basic_publish($msg, '', 'task_queue');
// 消费者
$channel->basic_qos(null, 1, null);
$channel->basic_consume('task_queue', '', false, false, false, false, function($msg) {
echo "Received: ", $msg->body, "\n";
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
});
Redis 列表(轻量级)
// 入队
$redis->rpush('task_queue', json_encode(['task' => 'send_email', 'data' => [...]]));
// 出队处理(守护进程)
while ($task = $redis->blpop('task_queue', 5)) {
$data = json_decode($task[1], true);
// 处理任务
}
进程管理工具
Supervisord
[program:worker] command=php /path/to/worker.php process_name=%(program_name)s_%(process_num)02d numprocs=4 autostart=true autorestart=true user=www-data
Gearman(分布式任务系统)
// 客户端
$client = new GearmanClient();
$client->addServer('127.0.0.1', 4730);
$result = $client->doBackground('send_email', json_encode($data));
// Worker
$worker = new GearmanWorker();
$worker->addServer('127.0.0.1', 4730);
$worker->addFunction('send_email', 'sendEmailHandler');
function sendEmailHandler($job) {
$data = json_decode($job->workload(), true);
// 处理邮件发送
}
异步 HTTP 请求
Guzzle 异步客户端
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
$client = new Client();
$promises = [
'request1' => $client->getAsync('http://api1.example.com'),
'request2' => $client->getAsync('http://api2.example.com'),
];
// 等待所有请求完成
$results = Promise\unwrap($promises);
// 或者只等待第一个完成
$first = Promise\settle($promises)['request1'];
Swoole 协程
use Swoole\Coroutine\Http\Client;
Coroutine\run(function () {
$client = new Client('api.example.com', 80);
$client->get('/endpoint1');
// 继续执行其他代码
echo "完成异步请求\n";
});
任务队列平台
Beanstalkd
use Pheanstalk\Pheanstalk;
$pheanstalk = Pheanstalk::create('127.0.0.1');
// 放入队列
$pheanstalk->useTube('email')->put($jobData);
// 消费任务
$job = $pheanstalk->watch('email')->reserve();
$data = json_decode($job->getData(), true);
// 处理任务
$pheanstalk->delete($job);
扩展库和框架
Laravel Queues
// 创建任务
class SendEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(private $user) {}
public function handle(EmailService $service)
{
$service->send($this->user);
}
}
// 派发任务
SendEmail::dispatch($user)->onQueue('emails');
// 延迟执行
SendEmail::dispatch($user)->delay(now()->addMinutes(10));
Symfony Messenger
// 消息类
class SendEmailMessage
{
public function __construct(private string $email) {}
}
// 发送消息
$this->messageBus->dispatch(new SendEmailMessage($email));
// 异步处理配置
messenger:
transports:
async:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
其他方案
PCNTL(进程控制)
$pid = pcntl_fork();
if ($pid == -1) {
die('无法创建子进程');
} elseif ($pid) {
// 父进程继续执行
echo "父进程继续\n";
} else {
// 子进程处理任务
processTask();
exit(0);
}
Workerman
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
$worker = new Worker('tcp://0.0.0.0:1234');
$worker->onMessage = function(TcpConnection $connection, $data) {
$connection->send('异步处理结果');
};
Worker::runAll();
云服务
- AWS SQS + Lambda
- 阿里云 MNS
- 腾讯云 CMQ
选型建议
| 场景 | 推荐方案 |
|---|---|
| 简单任务队列 | Redis + 后台脚本 |
| 复杂业务系统 | RabbitMQ / Kafka |
| 需要实时性 | Swoole / Workerman |
| 分布式系统 | Gearman / 云服务 |
| 框架生态 | Laravel Queue / Symfony Messenger |
| 轻量级异步请求 | Guzzle 异步 |
注意事项
- 任务幂等性:确保任务重复执行不会产生问题
- 失败重试:实现合理的重试机制
- 超时控制:设置合理的超时时间
- 日志记录:完整记录任务处理情况
- 监控告警:监控队列堆积和消费情况
- 并发控制:根据服务能力调整并发数
选择具体方案时,应综合考虑系统规模、团队技术栈、部署环境等因素。