谢邀.
如果你们有RabbitMQ的构架和经验, 实现这个很方便
rabbitmq 消息的消费端 channel 可以设置 prefetch=5, 即最多同时处理5条消息
rabbitmq 还有完善的ack机制, 即消息回执(该消息已正确处理完毕, 给我下条消息吧)
而且, 不会堵塞你当前PHP的进程, 后台(消费worker)会以5个并发的情形, 慢慢处理完这些任务
简单的可从Redis的List入手, 堵塞时判断队列的长度, 小于5时才开始popen并追加到队列
test.php
$redis = new \Redis();
$redis->connect("127.0.0.1", 6379);
$queue_name = "myqueue";
$queue_prefetch = 5;
$redis->delete($queue_name); // delete fro reseting.
for($i=0; $i<17; $i++){
while(1){
$count = count($redis->lRange($queue_name, 0, -1));
if($count <= $queue_prefetch) break;
usleep(20); // 堵塞20ms, 视情况而定, 太低redis I/O 会比较频繁
}
$redis->rPush($queue_name, $i);
$pid = pcntl_fork(); // 开启子进程, 需要pcntl模块
if($pid){
pclose(popen("/usr/bin/php /diandao/script.php $i $pid $queue_name", "w"));
pcntl_wait($status);
}
}
/diandao/script.php
sleep(1); // 模拟处理超过1秒
$index = $argv[1];
$pid = $argv[2];
$queue = $argv[3];
$redis = new Redis;
$redis->connect("127.0.0.1", 6379);
$f = fopen("/diandao/script.log", "a+");
$date = date("Y-m-d H:i:s");
fwrite($f, "[$date] ".json_encode($argv).PHP_EOL );
fclose($f);
$redis->lRem($queue, $index);
/diandao/script.log 结果
数量判断那多写了个=号, 所以并发变成了6个