zoukankan      html  css  js  c++  java
  • php实现多进程、多线程

      孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

      僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

      僵尸进程危害:如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。

      已经产生的僵尸进程,解决方法:kill掉父进程,它产生的僵死进程就变成了孤儿进 程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源。

      僵尸进程解决办法

      (1)通过信号机制

        子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。

      (2)fork两次
        《Unix 环境高级编程》8.6节说的非常详细。原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。

    多进程与多线程比较

    对比维度

    多进程

    多线程

    总结

    数据共享、同步

    数据共享复杂,需要用IPC;数据是分开的,同步简单

    因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂

    各有优势

    内存、CPU

    占用内存多,切换复杂,CPU利用率低

    占用内存少,切换简单,CPU利用率高

    线程占优

    创建销毁、切换

    创建销毁、切换复杂,速度慢

    创建销毁、切换简单,速度很快

    线程占优

    编程、调试

    编程简单,调试简单

    编程复杂,调试复杂

    进程占优

    可靠性

    进程间不会互相影响

    一个线程挂掉将导致整个进程挂掉

    进程占优

    分布式

    适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单

    适应于多核分布式

    进程占优

    1)需要频繁创建销毁的优先用线程

    原因请看上面的对比。

    这种原则最常见的应用就是Web服务器了,来一个连接建立一个线程,断了就销毁线程,要是用进程,创建和销毁的代价是很难承受的

    2)需要进行大量计算的优先使用线程

    所谓大量计算,当然就是要耗费很多CPU,切换频繁了,这种情况下线程是最合适的。

    这种原则最常见的是图像处理、算法处理。

    3)强相关的处理用线程,弱相关的处理用进程

    什么叫强相关、弱相关?理论上很难定义,给个简单的例子就明白了。

    一般的Server需要完成如下任务:消息收发、消息处理。“消息收发”和“消息处理”就是弱相关的任务,而“消息处理”里面可能又分为“消息解码”、“业务处理”,这两个任务相对来说相关性就要强多了。因此“消息收发”和“消息处理”可以分进程设计,“消息解码”、“业务处理”可以分线程设计。

    当然这种划分方式不是一成不变的,也可以根据实际情况进行调整。

    4)可能要扩展到多机分布的用进程,多核分布的用线程

    原因请看上面对比。

    5)都满足需求的情况下,用你最熟悉、最拿手的方式

    至于“数据共享、同步”、“编程、调试”、“可靠性”这几个维度的所谓的“复杂、简单”应该怎么取舍,我只能说:没有明确的选择方法。但我可以告诉你一个选择原则:如果多进程和多线程都能够满足要求,那么选择你最熟悉、最拿手的那个。 

    需要提醒的是:虽然我给了这么多的选择原则,但实际应用中基本上都是“进程+线程”的结合方式,千万不要真的陷入一种非此即彼的误区。

    消耗资源:

    从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。线程是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。

    线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。

    通讯方式:

    进程之间传递数据只能是通过通讯的方式,即费时又不方便。线程时间数据大部分共享(线程函数内部不共享),快捷方便。但是数据同步需要锁对于static变量尤其注意

    线程自身优势:

    提高应用程序响应;使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上;

    改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

     

    1. [代码]PHP实现多进程并行操作(可做守护进程) 

     1 /**
     2  * 入口函数
     3  * 将此文件保存为 ProcessOpera.php
     4  * 在terminal中运行 /usr/local/php/bin/php ProcessOpera.php & 
     5  * 查看进程 ps aux|grep php
     6  */
     7  
     8  
     9 ProcessOpera("runCode", array(), 8);
    10  
    11 /**
    12  * run Code
    13  */
    14 function runCode($opt = array()) {
    15    //需要在守护进程中运行的代码
    16 }
    17  
    18 /**
    19  * $func为子进程执行具体事物的函数名称
    20  * $opt为$func的参数 数组形式
    21  * $pNum 为fork的子进程数量
    22  */
    23 function ProcessOpera($func, $opts = array(), $pNum = 1) {
    24     while(true) {
    25         $pid = pcntl_fork();
    26         if($pid == -1) {
    27             exit("pid fork error");
    28         }   
    29         if($pid) {
    30             static $execute = 0;
    31             $execute++;
    32             if($execute >= $pNum) {
    33                 pcntl_wait($status);
    34                 $execute--;
    35             }   
    36         } else {
    37             while(true) {
    38                 //somecode
    39                 $func($opts);
    40                 sleep(1);
    41             }   
    42             exit(0);
    43         }   
    44     }   
    45 }

    2. [代码]PHP实现多线程操作 

     1 class My extends Thread {
     2     protected $name;
     3     public $runing;
     4     function __construct($name){
     5         $this->runing=1;
     6         $this->param=0;
     7         $this->name=$name;
     8     }
     9     public function run() {
    10         while($this->runing){
    11             if($this->param){
    12                 $time=rand(1,5);
    13                 echo 'I am thread '.$this->name.',pid: '.$this->getCreatorId().",param: {$this->param},need {$time}s
    "; 
    14                 sleep($time);
    15                 $this->param=0;
    16             }else{
    17                 echo "Thread {$this->name} waiting...
    ";
    18             }
    19             sleep(1);
    20         }
    21     }
    22 }
    23 $pool=array();
    24 $pool[]=new My('a');
    25 $pool[]=new My('b');
    26 $pool[]=new My('c');
    27 //开启所有线程
    28 foreach ($pool as $w) {
    29     $w->start();
    30 }
    31 //派发任务
    32 unset($w);
    33 for($i=1;$i<10;$i++){
    34     $woker_content=$i;
    35     while(1){
    36         foreach($pool as $w){
    37             if(!$w->param){
    38                 $w->param=$woker_content;
    39                 echo "Thread {$w->name} empty,put param {$woker_content}.
    ";
    40                 break 2;
    41             }
    42         }
    43         sleep(1);    
    44     }
    45 }
    46 
    47 unset($w);
    48 while(count($pool)){
    49     foreach ($pool as $k => $w) {
    50         if(!$w->param){
    51             $w->runing=false;
    52             unset($pool[$k]);
    53             echo "Thread {$w->name} end,exit!
    ";
    54         }
    55     }
    56     sleep(1);
    57 }
    58 
    59 echo 'All thread end!';
  • 相关阅读:
    20070521_新疆出差纪实
    有想应聘技术咨询顾问职位的朋友请看过来
    Access:運作必須查詢3/19
    我們是好朋友1/3
    小說學習1/22
    [Asp.net]動態設定標簽寬度2/22
    [Asp.net]HyperLinkColumn應用2/28
    [Asp.net]重啟IIS2/29
    [Asp.NET]水晶報表與網路密碼2/27
    把學習量化3/6
  • 原文地址:https://www.cnblogs.com/binghuo000/p/php_thread.html
Copyright © 2011-2022 走看看