溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么在PHP中使用process模塊創(chuàng)建子進(jìn)程

發(fā)布時間:2021-03-20 16:05:20 來源:億速云 閱讀:155 作者:Leah 欄目:開發(fā)技術(shù)

本篇文章給大家分享的是有關(guān)怎么在PHP中使用process模塊創(chuàng)建子進(jìn)程,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

swoole中為我們提供了一個進(jìn)程管理模塊 Process,替換PHP的 pcntl 擴(kuò)展,方便我們創(chuàng)建進(jìn)程,管理進(jìn)程,和進(jìn)程間的通信。

swoole提供了2種進(jìn)程間的通信:

1、基于 unix socket 的管道 pipe。

2、基于 sysvmsg 的消息隊列。

我們可以通過 new swoole_process() 快速的創(chuàng)建一個進(jìn)程,默認(rèn)會創(chuàng)建一個 SOCK_DGRAM 類型的管道,用于進(jìn)程間的通信,當(dāng)然可以設(shè)置成其他類型,也可以不創(chuàng)建。

一、通過同步阻塞管道進(jìn)行進(jìn)程間通信

<?php
$worker_process_nums = 5;
$worker_process = [];
 
for ($i = 0; $i < $worker_process_nums; $i++) {
  //創(chuàng)建子進(jìn)程
  //默認(rèn)為每個子進(jìn)程創(chuàng)建一個管道,如果不想創(chuàng)建設(shè)置$pipe_type參數(shù)為false
  //注意管道默認(rèn)是同步阻塞,半雙工,如果讀取不到數(shù)據(jù)就會阻塞
  $worker = new swoole_process(function (swoole_process $worker) {
    //注意,如果主進(jìn)程中不寫數(shù)據(jù)write(),那么子進(jìn)程這里read()就會阻塞
    $task = json_decode($worker->read(), true);
 
    //進(jìn)行計算任務(wù)
    $tmp = 0;
    for ($i = $task['start']; $i < $task['end']; $i++) {
      $tmp += $i;
    }
 
    echo '子進(jìn)程 PID : ', $worker->pid, ' 計算 ', $task['start'], ' - ', $task['end'], ' 結(jié)果 : ', $tmp, PHP_EOL;
    //往管道中寫入計算的結(jié)果
    $worker->write($tmp);
    //子進(jìn)程退出
    $worker->exit();
  });
 
  //保存子進(jìn)程
  $worker_process[$i] = $worker;
 
  //啟動子進(jìn)程
  $worker->start();
}
 
//往每個子進(jìn)程管道中投遞任務(wù)
for ($i = 0; $i < $worker_process_nums; $i++) {
  $worker_process[$i]->write(json_encode([
    'start' => mt_rand(1, 10),
    'end' => mt_rand(50, 100),
  ]));
}
 
//父進(jìn)程監(jiān)聽子進(jìn)程退出信號,回收子進(jìn)程,防止出現(xiàn)僵尸進(jìn)程
swoole_process::signal(SIGCHLD, function ($sig) {
  //必須為false,非阻塞模式
  while ($ret = swoole_process::wait(false)) {
    echo "子進(jìn)程 PID : {$ret['pid']} 退出\n";
  }
});

二、通過 swoole_event_add 將管道設(shè)為異步,來進(jìn)行通信

<?php
$worker_process_nums = 5;
$worker_process = [];
 
for ($i = 0; $i < $worker_process_nums; $i++) {
  $worker = new swoole_process(function ($worker) {
    //在子進(jìn)程中給管道添加事件監(jiān)聽
    //底層會自動將該管道設(shè)置為非阻塞模式
    //參數(shù)二,是可讀事件回調(diào)函數(shù),表示管道可以讀了
    swoole_event_add($worker->pipe, function ($pipe) use ($worker) {
      $task = json_decode($worker->read(), true);
 
      $tmp = 0;
      for ($i = $task['start']; $i < $task['end']; $i++) {
        $tmp += $i;
      }
      echo "子進(jìn)程 : {$worker->pid} 計算 {$task['start']} - {$task['end']} \n";
      //子進(jìn)程把計算的結(jié)果,寫入管道
      $worker->write($tmp);
      //注意,swoole_event_add與swoole_event_del要成對使用
      swoole_event_del($worker->pipe);
      //退出子進(jìn)程
      $worker->exit();
    });
  });
 
  $worker_process[$i] = $worker;
 
  //啟動子進(jìn)程
  $worker->start();
}
 
for ($i = 0; $i < $worker_process_nums; $i++) {
  $worker = $worker_process[$i];
 
  $worker->write(json_encode([
    'start' => mt_rand(1, 10),
    'end' => mt_rand(50, 100),
  ]));
 
  //主進(jìn)程中,監(jiān)聽子進(jìn)程管道事件
  swoole_event_add($worker->pipe, function ($pipe) use ($worker) {
    $result = $worker->read();
    echo "子進(jìn)程 : {$worker->pid} 計算結(jié)果 {$result} \n";
    swoole_event_del($worker->pipe);
  });
}
 
//父進(jìn)程監(jiān)聽子進(jìn)程退出信號,回收子進(jìn)程,防止出現(xiàn)僵尸進(jìn)程
swoole_process::signal(SIGCHLD, function ($sig) {
  //必須為false,非阻塞模式
  while ($ret = swoole_process::wait(false)) {
    echo "子進(jìn)程 PID : {$ret['pid']} 退出\n";
  }
});

三、使用消息隊列來完成進(jìn)程間通信

<?php
$worker_process_nums = 5;
$worker_process = [];
 
for ($i = 0; $i < $worker_process_nums; $i++) {
  //注意,這里將參數(shù)$pipe_type設(shè)為false,表示不創(chuàng)建管道
  $worker = new swoole_process(function ($worker) {
    $task = json_decode($worker->pop(), true);
 
    $tmp = 0;
    for ($i = $task['start']; $i < $task['end']; $i++) {
      $tmp += $i;
    }
    echo "子進(jìn)程 : {$worker->pid} 計算 {$task['start']} - {$task['end']} \n";
    $worker->push($tmp);
    $worker->exit();
  }, false, false);
 
  //使用消息隊列,作為進(jìn)程間的通信
  //注意,消息隊列是共享的
  $worker->useQueue();
 
  $worker_process[$i] = $worker;
 
  //啟動子進(jìn)程
  $worker->start();
}
 
for ($i = 0; $i < $worker_process_nums; $i++) {
  //只需用一個子進(jìn)程發(fā)送消息即可,因為消息隊列是共享的
  $worker_process[0]->push(json_encode([
    'start' => mt_rand(1, 10),
    'end' => mt_rand(50, 100),
  ]));
}
 
//注意,這里要暫停,防止加入隊列的任務(wù),立刻被主進(jìn)程讀出來。
sleep(1);
 
for ($i = 0; $i < $worker_process_nums; $i++) {
  $result = $worker_process[0]->pop();
  echo "計算結(jié)果 : {$result} \n";
}
 
//父進(jìn)程監(jiān)聽子進(jìn)程退出信號,回收子進(jìn)程,防止出現(xiàn)僵尸進(jìn)程
swoole_process::signal(SIGCHLD, function ($sig) {
  //必須為false,非阻塞模式
  while ($ret = swoole_process::wait(false)) {
    echo "子進(jìn)程 PID : {$ret['pid']} 退出\n";
  }
});

四、進(jìn)程可以通過 signal 監(jiān)聽信號,和 alarm 設(shè)置定時器。

我們可以在父進(jìn)程上設(shè)置監(jiān)聽信號,當(dāng)子進(jìn)程退出時,重新掛起子進(jìn)程。

也可以設(shè)置定時器,通過 swoole_process::kill($pid, 0); 定時檢測進(jìn)程是否存活。

<?php
//每隔1秒觸發(fā)SIGALAM信號
//注意,alarm不能和Timer同時使用
swoole_process::alarm(1000 * 1000, 0);
 
swoole_process::signal(SIGALRM, function ($signo) {
  static $cnt = 0;
  $cnt++;
  echo "時鐘定時信號\n";
 
  if ($cnt > 10) {
    //清除定時器
    swoole_process::alarm(-1);
  }
});
 
swoole_process::signal(SIGINT, function ($signo) {
  echo "我被ctrl+c了\n";
 
  //退出主進(jìn)程,不然將一直無法正常退出
  exit(0);
});

以上就是怎么在PHP中使用process模塊創(chuàng)建子進(jìn)程,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI