最近在写一个数据分析系统(亿级数据),由于循环从数据库读取数据库,数据处理量较大,会造成进程崩掉。后来想到了使用多进程的办法来解决,使用循环创建多个子进程的方式来分布到各个采集节点上,再着
要先修改下PHP.INItimeout时间,再修改下my.cnf的write_time时间,不废话,都改成120,充分发挥linux多任务的优势.不曾想多线程没用成反到是带来了一系列的意外收获.让之后的许多问题迎刃而解,不敢独享特一一道来.
本文所讲的东西是源自php的pcntl_fork函数.因为这个函数依赖操作系统fork的实现,所以本文所讲的东西只适用于linux/unix.ok,那么先看看这个函数的用法吧.
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
}
通过pcntl_fork创建一个子进程,如果返回值是-1的话,那么说明子进程创建失败.创建成功的进程id会返回给父进程,0返回给子进程.不好理解吧,费了很常时间明白以后,笔者习惯这样写:
$pid = pcntl_fork();
if($pid == -1){
//创建失败咱就退出呗,没啥好说的
die('could not fork');
}
else{
if($pid){
//从这里开始写的代码是父进程的,因为写的是系统程序,记得退出的时候给个返回值
exit("I am parent!");
}
else{
//从这里开始写的代码都是在新的进程里执行的,同样正常退出的话,最好也给一个返回值
exit("I am child");
}
}
补充:上述代码如果创建子进程成功的话,那么系统就有了两个进程,一个父进程,一个子进程。这两个进程的代码是完全相同的,只是系统分配给他们的内存等资源不一样,因为他们是独立的进程;代码运行的结果是 "I an parent!" "I amchild",不要惊讶于为什么if语句里面的两个条件结果都执行了。其实是个表象,真相是父进程执行了一遍代码,由于pcntl_fork() 函数返回的是子进程的pid数,这个数是大于0的,所以执行的分支是exit("I amparent!");而子进程在执行的时候,操作系统给pcntl_fork()函数返回的是0.所以执行的分支是exit("I amchild");至于是让父进程先执行还是让子进程先执行,这个问题可以通过别的方法实现)
1.后台程序
官方的一个CODE:
Fork in foreach:
<?php
foreach ($tasks as $v)
{if (($pid=pcntl_fork())===-1)
{//...
continue;
}
else if ($pid)
{pcntl_wait($status, WNOHANG); //protect against zombie children, one wait vs one child
}
else if ($pid===0)
{ob_start();//prevent output to main process
register_shutdown_function(create_function('$pars', 'ob_end_clean();posix_kill(getmypid(), SIGKILL);'), array());//to kill self before exit();, or else the resource shared with parent will be closed
//...
exit();//avoid foreach loop in child process
}
}
?>