溫馨提示×

溫馨提示×

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

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

PHP多進程與信號中斷如何實現(xiàn)多任務(wù)常駐內(nèi)存管理

發(fā)布時間:2021-07-28 09:13:29 來源:億速云 閱讀:169 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹了PHP多進程與信號中斷如何實現(xiàn)多任務(wù)常駐內(nèi)存管理,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

進程調(diào)度策略

父子進程的調(diào)度由操作系統(tǒng)來負責,具體先調(diào)度子進程還是父進程由系統(tǒng)的調(diào)度算法決定,當然可以在父進程加上延時或是調(diào)用進程回收函數(shù) pcntl_wait 可以先讓子進程先運行,進程回收的目的是釋放進程創(chuàng)建時占用的內(nèi)存空間,防止變成僵尸進程。

信號:

信號稱為軟中斷系統(tǒng)或是叫軟中斷,功能是向進程發(fā)送異步事件通知。

信號編號: 【源碼基于 SIGINT,SIGTERM,SIGUSR1 信號,含義請自行查看 kill 命令手冊,不在描述】

linux 支持 64 個,有一半為實時信號,一半為非時實信號,這些信號都有自己的編號和對應的整數(shù)值。每個信號的編號含義讀者可以參閱 linux 相關(guān)手冊【man 手冊看看就知道了】

信號處理函數(shù):

信號一般會綁定相應的功能,有的是默認動作如 SIGKILL,SIGTERM,SIGINT 操作默認操作就是干掉進程,當然我們可以重寫覆蓋掉,就是通過 pcntl_signal 來覆蓋掉。

信號的概念:與硬件中斷一個道理,請讀者自行參考本人前面擼過的文章或是查看芯片硬件中斷原理。

信號的發(fā)送:

kill 信號編號 進程 或是按鍵產(chǎn)品的中斷信號或是在源碼里可以使用 posix_kill 等函數(shù)。

進程是相互隔離的,擁有自己的堆??臻g,除了一些公用的正文【代碼區(qū)】,同時也有自己的可執(zhí)行代碼,進程運行時,將占用 cpu 的資源,其它進程將無權(quán)運行,此時其它進程將為阻塞狀態(tài)【比如前面擼過的 tcp 服務(wù)】,當進程運行結(jié)束后【運行到代碼的最后一句或是遇到 return 或是遇到 exit 退出進程函數(shù)或是遇到信號事件時將會退出】讓出權(quán)限并釋放掉內(nèi)存,其它進程就有機會運行了。

進程擁有的自己進程描述符,其中比較常用的是進程號 PID,進程運行時會在系統(tǒng) /proc/PID 下生成相應的進程文件,用戶可以自行查看。

每個進程都擁有所屬的進程組【進程的集合】,多個進程組集合則是一個會話,創(chuàng)建一個會話是通過一個進程進行創(chuàng)建的,并且此進程不可以為組長進程,此進程將成為會話期的會話首進程,也會成為進程組的進程組長,同時將會脫離控制終端,即使之前的進程綁定了控制終端也會脫離【守護進程的創(chuàng)建】。

文件描述權(quán)限掩碼【權(quán)限屏蔽字】:

umask () 你可以在 linux 運行這個命令,然后創(chuàng)建文件,并查看它的權(quán)限【如果你跑完啥也沒有發(fā)現(xiàn),說明你還是訓練不夠 ^_^】

<?php

/**

 * Created by PhpStorm.

 * User: 1655664358@qq.com

 * Date: 2018/3/26

 * Time: 14:19

 */

namespace Chen\Worker;

class Server

{

 public $workerPids = [];

 public $workerJob = [];

 public $master_pid_file = "master_pid";

 public $state_file = "state_file.txt";

 function run()

 {

  $this->daemon();

  $this->worker();

  $this->setMasterPid();

  $this->installSignal();

  $this->showState();

  $this->wait();

 }

 function wait()

 {

  while (1){

   pcntl_signal_dispatch();

   $pid = pcntl_wait($status);

   if ($pid>0){

    unset($this->workerPids[$pid]);

   }else{

    if (count($this->workerPids)==0){

     exit();

    }

   }

   usleep(100000);

  }

 }

 function showState()

 {

  $state = "\nMaster 信息\n";

  $state.=str_pad("master pid",25);

  $state.=str_pad("worker num",25);

  $state.=str_pad("job pid list",10)."\n";

  $state.=str_pad($this->getMasterPid(),25);

  $state.=str_pad(count($this->workerPids),25);

  $state.=str_pad(implode(",",array_keys($this->workerPids)),10);

  echo $state.PHP_EOL;

 }

 function getMasterPid()

 {

  if (file_exists($this->master_pid_file)){

   return file_get_contents($this->master_pid_file);

  }else{

   exit("服務(wù)未運行\(zhòng)n");

  }

 }

 function setMasterPid()

 {

  $fp = fopen($this->master_pid_file,"w");

  @fwrite($fp,posix_getpid());

  @fclose($fp);

 }

 function daemon()

 {

  $pid = pcntl_fork();

  if ($pid<0){

   exit("fork進程失敗\n");

  }else if ($pid >0){

   exit(0);

  }else{

   umask(0);

   $sid = posix_setsid();

   if ($sid<0){

    exit("創(chuàng)建會話失敗\n");

   }

   $pid = pcntl_fork();

   if ($pid<0){

    exit("進程創(chuàng)建失敗\n");

   }else if ($pid >0){

    exit(0);

   }

   //可以關(guān)閉標準輸入輸出錯誤文件描述符【守護進程不需要】

  }

 }

 function worker()

 {

  if (count($this->workerJob)==0)exit("沒有工作任務(wù)\n");

  foreach($this->workerJob as $job){

   $pid = pcntl_fork();

   if ($pid<0){

    exit("工作進程創(chuàng)建失敗\n");

   }else if ($pid==0){

    /***************子進程工作范圍**********************/

    //給子進程安裝信號處理程序

    $this->workerInstallSignal();

    $start_time = time();

    while (1){

     pcntl_signal_dispatch();

     if ((time()-$start_time)>=$job->job_run_time){

      break;

     }

     $job->run(posix_getpid());

    }

    exit(0);//子進程運行完成后退出

    /***************子進程工作范圍**********************/

   }else{

    $this->workerPids[$pid] = $job;

   }

  }

 }

 function workerInstallSignal()

 {

  pcntl_signal(SIGUSR1,[__CLASS__,'workerHandleSignal'],false);

 }

 function workerHandleSignal($signal)

 {

  switch ($signal){

   case SIGUSR1:

    $state = "worker pid=".posix_getpid()."接受了父進程發(fā)來的自定義信號\n";

    file_put_contents($this->state_file,$state,FILE_APPEND);

    break;

  }

 }

 function installSignal()

 {

  pcntl_signal(SIGINT,[__CLASS__,'handleMasterSignal'],false);

  pcntl_signal(SIGTERM,[__CLASS__,'handleMasterSignal'],false);

  pcntl_signal(SIGUSR1,[__CLASS__,'handleMasterSignal'],false);

 }

 function handleMasterSignal($signal)

 {

  switch ($signal){

   case SIGINT:

    //主進程接受到中斷信號ctrl+c

    foreach ($this->workerPids as $pid=>$worker){

     posix_kill($pid,SIGINT);//向所有的子進程發(fā)出

    }

    exit("服務(wù)平滑停止\n");

    break;

   case SIGTERM://ctrl+z

    foreach ($this->workerPids as $pid=>$worker){

     posix_kill($pid,SIGKILL);//向所有的子進程發(fā)出

    }

    exit("服務(wù)停止\n");

    break;

   case SIGUSR1://用戶自定義信號

    if (file_exists($this->state_file)){

     unlink($this->state_file);

    }

    foreach ($this->workerPids as $pid=>$worker){

     posix_kill($pid,SIGUSR1);

    }

    $state = "master pid\n".$this->getMasterPid()."\n";

    while(!file_exists($this->state_file)){

     sleep(1);

    }

    $state.= file_get_contents($this->state_file);

    echo $state.PHP_EOL;

    break;

  }

 }

} 

<?php

/**\

 * Created by PhpStorm.\ * User: 1655664358@qq.com

 * Date: 2018/3/26\ * Time: 14:37\ */\namespace Chen\Worker;

class Job

{

 public $job_run_time = 3600;

 function run($pid)

 {\sleep(3);

 echo "worker pid = $pid job 沒事干,就在這里job\n";

 }

} 

<?php

/**

 * Created by PhpStorm.\ * User: 1655664358@qq.com

 * Date: 2018/3/26\ * Time: 14:37\ */\namespace Chen\Worker;

class Talk

{

 public $job_run_time = 3600;

 function run($pid)

 {\sleep(3);

 echo "worker pid = $pid job 沒事干,就在這里talk\n";

 }

}

<?php

/**

 * Created by PhpStorm.\ * User: 1655664358@qq.com

 * Date: 2018/3/26\ * Time: 15:45\ */

require_once 'vendor/autoload.php';

$process = new \Chen\Worker\Server();

$process->workerJob = [new \Chen\Worker\Talk(),new \Chen\Worker\Job()];

$process->run();

PHP多進程與信號中斷如何實現(xiàn)多任務(wù)常駐內(nèi)存管理

感謝你能夠認真閱讀完這篇文章,希望小編分享的“PHP多進程與信號中斷如何實現(xiàn)多任務(wù)常駐內(nèi)存管理”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識等著你來學習!

向AI問一下細節(jié)

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

php
AI