设为首页 收藏本站
查看: 809|回复: 0

[经验分享] php实现多进程、多线程

[复制链接]

尚未签到

发表于 2017-12-29 16:41:15 | 显示全部楼层 |阅读模式
  孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被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实现多进程并行操作(可做守护进程)
  

/**  

* 入口函数  

* 将此文件保存为 ProcessOpera.php  

* 在terminal中运行 /usr/local/php/bin/php ProcessOpera.php &  

* 查看进程 ps aux|grep php  

*/  

  

  
ProcessOpera("runCode", array(), 8);
  

  
/**
  
  * run Code
  
  */
  
function runCode($opt = array()) {
  
    //需要在守护进程中运行的代码
  
}
  

  
/**
  
  * $func为子进程执行具体事物的函数名称
  
  * $opt为$func的参数 数组形式
  
  * $pNum 为fork的子进程数量
  
  */
  
function ProcessOpera($func, $opts = array(), $pNum = 1) {
  
     while(true) {
  
         $pid = pcntl_fork();
  
         if($pid == -1) {
  
             exit("pid fork error");
  
         }
  
         if($pid) {
  
             static $execute = 0;
  
             $execute++;
  
             if($execute >= $pNum) {
  
                 pcntl_wait($status);
  
                 $execute--;
  
             }
  
         } else {
  
             while(true) {
  
                 //somecode
  
                 $func($opts);
  
                 (1);
  
             }
  
             exit(0);
  
         }
  
     }
  
}
  


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

>
protected $name;  

public $runing;  

function __construct($name){  

$this->runing=1;  

$this->param=0;  

$this->name=$name;  

}  

public function run() {  

while($this->runing){  

if($this->param){  

$time=(1,5);  

echo 'I am thread '.$this->name.',pid: '.$this->getCreatorId().",param: {$this->param},need {$time}s\n";  

($time);  

$this->param=0;  

}else{  

echo "Thread {$this->name} waiting...\n";  

}  

(1);  

}  

}  

}  

$pool=array();  

$pool[]=new My('a');  

$pool[]=new My('b');  

$pool[]=new My('c');  

//开启所有线程  
foreach ($pool as $w) {
  
     $w->start();
  
}
  
//派发任务
  
unset($w);
  
for($i=1;$i<10;$i++){
  
     $woker_content=$i;
  
     while(1){
  
         foreach($pool as $w){
  
             if(!$w->param){
  
                 $w->param=$woker_content;
  
                 echo "Thread {$w->name} empty,put param {$woker_content}.\n";
  
                 break 2;
  
             }
  
         }
  
         (1);
  
     }
  
}
  

  
unset($w);
  
while(($pool)){
  
     foreach ($pool as $k => $w) {
  
         if(!$w->param){
  
             $w->runing=false;
  
             unset($pool[$k]);
  
             echo "Thread {$w->name} end,exit!\n";
  
         }
  
     }
  
     (1);
  
}
  

  
echo 'All thread end!';
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-429412-1-1.html 上篇帖子: php token的生成 下篇帖子: PHP保存数组到数据库
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表