当前位置:首页 > PHP教程 > php高级应用 > 列表

PHP swoole的process模块创建和使用子进程操作示例

发布:smiling 来源: PHP粉丝网  添加日期:2022-02-19 09:38:43 浏览: 评论:0 

本文实例讲述了PHP swoole的process模块创建和使用子进程操作,分享给大家供大家参考,具体如下:

swoole中为我们提供了一个进程管理模块 Process,替换PHP的 pcntl 扩展,方便我们创建进程,管理进程,和进程间的通信。

swoole提供了2种进程间的通信:

1、基于 unix socket 的管道 pipe。

2、基于 sysvmsg 的消息队列。

我们可以通过 new swoole_process() 快速的创建一个进程,默认会创建一个 SOCK_DGRAM 类型的管道,用于进程间的通信,当然可以设置成其他类型,也可以不创建。

一、通过同步阻塞管道进行进程间通信

  1. <?php 
  2. $worker_process_nums = 5; 
  3. $worker_process = []; 
  4.    
  5. for ($i = 0; $i < $worker_process_nums$i++) { 
  6.   //创建子进程 
  7.   //默认为每个子进程创建一个管道,如果不想创建设置$pipe_type参数为false 
  8.   //注意管道默认是同步阻塞,半双工,如果读取不到数据就会阻塞 
  9.   $worker = new swoole_process(function (swoole_process $worker) { 
  10.     //注意,如果主进程中不写数据write(),那么子进程这里read()就会阻塞 
  11.     $task = json_decode($worker->read(), true); 
  12.    
  13.     //进行计算任务 
  14.     $tmp = 0; 
  15.     for ($i = $task['start']; $i < $task['end']; $i++) { 
  16.       $tmp += $i
  17.     } 
  18.    
  19.     echo '子进程 PID : '$worker->pid, ' 计算 '$task['start'], ' - '$task['end'], ' 结果 : '$tmp, PHP_EOL; 
  20.     //往管道中写入计算的结果 
  21.     $worker->write($tmp); 
  22.     //子进程退出 
  23.     $worker->exit(); 
  24.   }); 
  25.    
  26.   //保存子进程 
  27.   $worker_process[$i] = $worker
  28.    
  29.   //启动子进程 
  30.   $worker->start(); 
  31.    
  32. //往每个子进程管道中投递任务 
  33. for ($i = 0; $i < $worker_process_nums$i++) { 
  34.   $worker_process[$i]->write(json_encode([ 
  35.     'start' => mt_rand(1, 10), 
  36.     'end' => mt_rand(50, 100), 
  37.   ])); 
  38.    
  39. //父进程监听子进程退出信号,回收子进程,防止出现僵尸进程 
  40. swoole_process::signal(SIGCHLD, function ($sig) { 
  41.   //必须为false,非阻塞模式 
  42.   while ($ret = swoole_process::wait(false)) { 
  43.     echo "子进程 PID : {$ret['pid']} 退出\n"
  44.   } 
  45. }); 

二、通过 swoole_event_add 将管道设为异步,来进行通信

  1. <?php 
  2. $worker_process_nums = 5; 
  3. $worker_process = []; 
  4.    
  5. for ($i = 0; $i < $worker_process_nums$i++) { 
  6.   $worker = new swoole_process(function ($worker) { 
  7.     //在子进程中给管道添加事件监听 
  8.     //底层会自动将该管道设置为非阻塞模式 
  9.     //参数二,是可读事件回调函数,表示管道可以读了 
  10.     swoole_event_add($worker->pipe, function ($pipeuse ($worker) { 
  11.       $task = json_decode($worker->read(), true); 
  12.    
  13.       $tmp = 0; 
  14.       for ($i = $task['start']; $i < $task['end']; $i++) { 
  15.         $tmp += $i
  16.       } 
  17.       echo "子进程 : {$worker->pid} 计算 {$task['start']} - {$task['end']} \n"
  18.       //子进程把计算的结果,写入管道 
  19.       $worker->write($tmp); 
  20.       //注意,swoole_event_add与swoole_event_del要成对使用 
  21.       swoole_event_del($worker->pipe); 
  22.       //退出子进程 
  23.       $worker->exit(); 
  24.     }); 
  25.   }); 
  26.    
  27.   $worker_process[$i] = $worker
  28.    
  29.   //启动子进程 
  30.   $worker->start(); 
  31.    
  32. for ($i = 0; $i < $worker_process_nums$i++) { 
  33.   $worker = $worker_process[$i]; 
  34.    
  35.   $worker->write(json_encode([ 
  36.     'start' => mt_rand(1, 10), 
  37.     'end' => mt_rand(50, 100), 
  38.   ])); 
  39.    
  40.   //主进程中,监听子进程管道事件 
  41.   swoole_event_add($worker->pipe, function ($pipeuse ($worker) { 
  42.     $result = $worker->read(); 
  43.     echo "子进程 : {$worker->pid} 计算结果 {$result} \n"
  44.     swoole_event_del($worker->pipe); 
  45.   }); 
  46.    
  47. //父进程监听子进程退出信号,回收子进程,防止出现僵尸进程 
  48. swoole_process::signal(SIGCHLD, function ($sig) { 
  49.   //必须为false,非阻塞模式 
  50.   while ($ret = swoole_process::wait(false)) { 
  51.     echo "子进程 PID : {$ret['pid']} 退出\n"
  52.   } 
  53. }); 

三、使用消息队列来完成进程间通信

  1. <?php 
  2. $worker_process_nums = 5; 
  3. $worker_process = []; 
  4.    
  5. for ($i = 0; $i < $worker_process_nums$i++) { 
  6.   //注意,这里将参数$pipe_type设为false,表示不创建管道 
  7.   $worker = new swoole_process(function ($worker) { 
  8.     $task = json_decode($worker->pop(), true); 
  9.    
  10.     $tmp = 0; 
  11.     for ($i = $task['start']; $i < $task['end']; $i++) { 
  12.       $tmp += $i
  13.     } 
  14.     echo "子进程 : {$worker->pid} 计算 {$task['start']} - {$task['end']} \n"
  15.     $worker->push($tmp); 
  16.     $worker->exit(); 
  17.   }, false, false); 
  18.    
  19.   //使用消息队列,作为进程间的通信 
  20.   //注意,消息队列是共享的 
  21.   $worker->useQueue(); 
  22.    
  23.   $worker_process[$i] = $worker
  24.    
  25.   //启动子进程 
  26.   $worker->start(); 
  27.    
  28. for ($i = 0; $i < $worker_process_nums$i++) { 
  29.   //只需用一个子进程发送消息即可,因为消息队列是共享的 
  30.   $worker_process[0]->push(json_encode([ 
  31.     'start' => mt_rand(1, 10), 
  32.     'end' => mt_rand(50, 100), 
  33.   ])); 
  34.    
  35. //注意,这里要暂停,防止加入队列的任务,立刻被主进程读出来。 
  36. sleep(1); 
  37.    
  38. for ($i = 0; $i < $worker_process_nums$i++) { 
  39.   $result = $worker_process[0]->pop(); 
  40.   echo "计算结果 : {$result} \n"
  41.    
  42. //父进程监听子进程退出信号,回收子进程,防止出现僵尸进程 
  43. swoole_process::signal(SIGCHLD, function ($sig) { 
  44.   //必须为false,非阻塞模式 
  45.   while ($ret = swoole_process::wait(false)) { 
  46.     echo "子进程 PID : {$ret['pid']} 退出\n"
  47.   } 
  48. }); 

四、进程可以通过 signal 监听信号,和 alarm 设置定时器。

我们可以在父进程上设置监听信号,当子进程退出时,重新挂起子进程。

也可以设置定时器,通过 swoole_process::kill($pid, 0); 定时检测进程是否存活。

  1. <?php 
  2. //每隔1秒触发SIGALAM信号 
  3. //注意,alarm不能和Timer同时使用 
  4. swoole_process::alarm(1000 * 1000, 0); 
  5.    
  6. swoole_process::signal(SIGALRM, function ($signo) { 
  7.   static $cnt = 0; 
  8.   $cnt++; 
  9.   echo "时钟定时信号\n"
  10.    
  11.   if ($cnt > 10) { 
  12.     //清除定时器 
  13.     swoole_process::alarm(-1); 
  14.   } 
  15. }); 
  16.    
  17. swoole_process::signal(SIGINT, function ($signo) { 
  18.   echo "我被ctrl+c了\n"
  19.    
  20.   //退出主进程,不然将一直无法正常退出 
  21.   exit(0); 
  22. });

Tags: swoole process PHP子进程

分享到: