php多进程编程二
2013-08-02 11:18
309 查看
php在pcntl_fork()后生成的子进程(通常为僵尸进程)必须由pcntl_waitpid()函数进行资源释放。但在pcntl_waitpid()不一定释放的就是当前运行的进程,也可能是过去生成的僵尸进程(没有释放);也可能是并发时其它访问者的僵尸进程。但可以 使用posix_kill($cid, SIGTERM)在子进程结束时杀掉它。
子进程会自动复制父进程空间里的变量。
PHP多进程编程示例2
如果不需要阻塞进程,而又想得到子进程的退出状态,则可以注释掉pcntl_wait($status)语句,或写成:
<?php
pcntl_wait($status,
1);
//或
pcntl_wait($status, WNOHANG);
在上面的代码中,如果父进程退出(使用exit函数退出或redirect),则会导致子进程成为僵尸进程(会交给init进程控制),子进程不再执行。
僵 尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程.(zombie)进程。任何进程在退出前(使用exit退出)都会变成 僵尸进程(用于保存进程的状态等信息),然后由init进程接管。如果不及时回收僵尸进程,那么它在系统中就会占用一个进程表项,如果这种僵尸进程过多, 最后系统就没有可以用的进程表项,于是也无法再运行其它的程序。
预防僵尸进程有以下几种方法:
父 进程通过wait和waitpid等函数使其等待子进程结束,然后再执行父进程中的代码,这会导致父进程挂起。上面的代码就是使用这种方式实现的,但在WEB环境下,它不适合子进程需要长时间运行的情况(会导致超时)。使用wait和waitpid方法使父进程自动回收其僵尸子进程(根据子进程的返回状 态),waitpid用于临控指定子进程,wait是对于所有子进程而言。
如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号,例如:pcntl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
//....code
还有一个技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程再fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自己做。下面是一个例子:
<
4000
/strong>[b]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "apue.h"
#include
int main(void){
pid_t pid;
if ((pid
= fork())
< 0){
err_sys("fork error");
} else
if (pid ==
0){
/**//* first child */
if ((pid
= fork())
< 0){
err_sys("fork error");
}elseif(pid
> 0){
exit(0);
/**//* parent from second fork == first child */
}
/**
* We're the second child; our parent becomes init as soon
* as our real parent calls exit() in the statement above.
* Here's where we'd continue executing, knowing that when
* we're done, init will reap our status.
*/
sleep(2);
printf("second child, parent pid = %d ", getppid());
exit(0);
}
if (waitpid(pid, NULL,
0)
!= pid) /**//* wait for first child */
err_sys("waitpid error");
/**
* We're the parent (the original process); we continue executing,
* knowing that we're not the parent of the second child.
*/
exit(0);
}
在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程,无法正常结束,此时即使是root身份kill-9也不能杀死僵尸进 程。补救办法是杀死僵尸进程的父进程(僵尸进程的父进程必然存在),僵尸进程成为”孤儿进程”,过继给1号进程init,init会定期调用wait回收
清理这些父进程已退出的僵尸子进程。
所以,上面的示例可以改成:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[b]<?php
//.....
//需要安装pcntl的php扩展,并加载它
if(function_exists("pcntl_fork")){
//生成第一个子进程
$pid = pcntl_fork();
//$pid即所产生的子进程id
if($pid
== -1){
//子进程fork失败
die('could not fork');
}else{
if($pid){
//父进程code
sleep(5);
//等待5秒
exit(0);
//或$this->_redirect('/');
}else{
//第一个子进程code
//产生孙进程
if(($gpid
= pcntl_fork())
< 0){
////$gpid即所产生的孙进程id
//孙进程产生失败
die('could not fork');
}elseif($gpid
> 0){
//第一个子进程code,即孙进程的父进程
$status =
0;
$status = pcntl_wait($status);
//阻塞子进程,并返回孙进程的退出状态,用于检查是否正常退出
if($status
! =
0) file_put_content('filename',
'孙进程异常退出');
//得到父进程id
//$ppid = posix_getppid(); //如果$ppid为1则表示其父进程已变为init进程,原父进程已退出
//得到子进程id:posix_getpid()或getmypid()或是fork返回的变量$pid
//kill掉子进程
//posix_kill(getmypid(), SIGTERM);
exit(0);
}else{
//即$gpid == 0
//孙进程code
//....
//结束孙进程(即当前进程),以防止生成僵尸进程
if(function_exists('posix_kill')){
posix_kill(getmypid(), SIGTERM);
}else{
system('kill -9'.
getmypid());
}
exit(0);
}
}
}
}else{
// 不支持多进程处理时的代码在这里
}
//.....
?>
怎样产生僵尸进程的[/b]
一 个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它 的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已 经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵
尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程 结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但 是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的 阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是”Z”。
9fb3
如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。
如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。
另外,还可以写一个php文件,然后在以后台形式来运行它,例如:
<?php
//Action代码
[b]public
function createAction(){
//....
//将args替换成要传给insertLargeData.php的参数,参数间用空格间隔
system('php -f insertLargeData.php '
. ' args '
. '&');
$this->redirect('/');
}
?>
然后在insertLargeData.php文件中做数据库操作。也可以用cronjob + php的方式实现大数据量的处理。
如果是在终端运行php命令,当终端关闭后,刚刚执行的命令也会被强制关闭,如果你想让其不受终端关闭的影响,可以使用nohup命令实现:
<?php
//Action代码
public
function createAction(){
//....
//将args替换成要传给insertLargeData.php的参数,参数间用空格间隔
system('nohup php -f insertLargeData.php '
. ' args '
. '&');
$this->redirect('/');
}
?>
[/b]
子进程会自动复制父进程空间里的变量。
PHP多进程编程示例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?php //..... //需要安装pcntl的php扩展,并加载它 if(function_exists("pcntl_fork")){ //生成子进程 $pid = pcntl_fork(); if($pid == -1){ die('could not fork'); }else{ if($pid){ $status = 0; //阻塞父进程,直到子进程结束,不适合需要长时间运行的脚本,可使用pcntl_wait($status, 0)实现非阻塞式 pcntl_wait($status); // parent proc code exit; }else{ // child proc code //结束当前子进程,以防止生成僵尸进程 if(function_exists("posix_kill")){ posix_kill(getmypid(), SIGTERM); }else{ system('kill -9'. getmypid()); } exit; } } }else{ // 不支持多进程处理时的代码在这里 } //..... [b]?>[/b] |
<?php
pcntl_wait($status,
1);
//或
pcntl_wait($status, WNOHANG);
在上面的代码中,如果父进程退出(使用exit函数退出或redirect),则会导致子进程成为僵尸进程(会交给init进程控制),子进程不再执行。
僵 尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程.(zombie)进程。任何进程在退出前(使用exit退出)都会变成 僵尸进程(用于保存进程的状态等信息),然后由init进程接管。如果不及时回收僵尸进程,那么它在系统中就会占用一个进程表项,如果这种僵尸进程过多, 最后系统就没有可以用的进程表项,于是也无法再运行其它的程序。
预防僵尸进程有以下几种方法:
父 进程通过wait和waitpid等函数使其等待子进程结束,然后再执行父进程中的代码,这会导致父进程挂起。上面的代码就是使用这种方式实现的,但在WEB环境下,它不适合子进程需要长时间运行的情况(会导致超时)。使用wait和waitpid方法使父进程自动回收其僵尸子进程(根据子进程的返回状 态),waitpid用于临控指定子进程,wait是对于所有子进程而言。
如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号,例如:pcntl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
//....code
还有一个技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程再fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自己做。下面是一个例子:
<
4000
/strong>[b]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "apue.h"
#include
int main(void){
pid_t pid;
if ((pid
= fork())
< 0){
err_sys("fork error");
} else
if (pid ==
0){
/**//* first child */
if ((pid
= fork())
< 0){
err_sys("fork error");
}elseif(pid
> 0){
exit(0);
/**//* parent from second fork == first child */
}
/**
* We're the second child; our parent becomes init as soon
* as our real parent calls exit() in the statement above.
* Here's where we'd continue executing, knowing that when
* we're done, init will reap our status.
*/
sleep(2);
printf("second child, parent pid = %d ", getppid());
exit(0);
}
if (waitpid(pid, NULL,
0)
!= pid) /**//* wait for first child */
err_sys("waitpid error");
/**
* We're the parent (the original process); we continue executing,
* knowing that we're not the parent of the second child.
*/
exit(0);
}
在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程,无法正常结束,此时即使是root身份kill-9也不能杀死僵尸进 程。补救办法是杀死僵尸进程的父进程(僵尸进程的父进程必然存在),僵尸进程成为”孤儿进程”,过继给1号进程init,init会定期调用wait回收
清理这些父进程已退出的僵尸子进程。
所以,上面的示例可以改成:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[b]<?php
//.....
//需要安装pcntl的php扩展,并加载它
if(function_exists("pcntl_fork")){
//生成第一个子进程
$pid = pcntl_fork();
//$pid即所产生的子进程id
if($pid
== -1){
//子进程fork失败
die('could not fork');
}else{
if($pid){
//父进程code
sleep(5);
//等待5秒
exit(0);
//或$this->_redirect('/');
}else{
//第一个子进程code
//产生孙进程
if(($gpid
= pcntl_fork())
< 0){
////$gpid即所产生的孙进程id
//孙进程产生失败
die('could not fork');
}elseif($gpid
> 0){
//第一个子进程code,即孙进程的父进程
$status =
0;
$status = pcntl_wait($status);
//阻塞子进程,并返回孙进程的退出状态,用于检查是否正常退出
if($status
! =
0) file_put_content('filename',
'孙进程异常退出');
//得到父进程id
//$ppid = posix_getppid(); //如果$ppid为1则表示其父进程已变为init进程,原父进程已退出
//得到子进程id:posix_getpid()或getmypid()或是fork返回的变量$pid
//kill掉子进程
//posix_kill(getmypid(), SIGTERM);
exit(0);
}else{
//即$gpid == 0
//孙进程code
//....
//结束孙进程(即当前进程),以防止生成僵尸进程
if(function_exists('posix_kill')){
posix_kill(getmypid(), SIGTERM);
}else{
system('kill -9'.
getmypid());
}
exit(0);
}
}
}
}else{
// 不支持多进程处理时的代码在这里
}
//.....
?>
怎样产生僵尸进程的[/b]
一 个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它 的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已 经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵
尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程 结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但 是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的 阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是”Z”。
9fb3
如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。
如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。
另外,还可以写一个php文件,然后在以后台形式来运行它,例如:
<?php
//Action代码
[b]public
function createAction(){
//....
//将args替换成要传给insertLargeData.php的参数,参数间用空格间隔
system('php -f insertLargeData.php '
. ' args '
. '&');
$this->redirect('/');
}
?>
然后在insertLargeData.php文件中做数据库操作。也可以用cronjob + php的方式实现大数据量的处理。
如果是在终端运行php命令,当终端关闭后,刚刚执行的命令也会被强制关闭,如果你想让其不受终端关闭的影响,可以使用nohup命令实现:
<?php
//Action代码
public
function createAction(){
//....
//将args替换成要传给insertLargeData.php的参数,参数间用空格间隔
system('nohup php -f insertLargeData.php '
. ' args '
. '&');
$this->redirect('/');
}
?>
[/b]
相关文章推荐
- php多进程编程相关资料(以备参考)
- PHP实现系统编程(五)--- 编写守护进程详解
- PHP多进程编程实例
- PHP多进程编程
- PHP多进程编程
- PHP系统编程--01.多进程与多线程
- PHP多进程编程实例
- PHP多进程编程
- PHP CLI编程基础知识积累(进程、子进程、线程)
- php信号量子进程编程
- PHP系统编程--01.多进程与多线程
- PHP多进程编程(3):多进程抓取网页的演示
- (转载)PCNTL函数族--PHP多进程编程
- PHP系统编程--03.PHP进程信号处理
- PHP多进程编程总结(推荐)
- php多进程编程详解
- PHP高级编程实例:编写守护进程
- php 多进程编程
- PHP多进程编程之僵尸进程问题
- PHP高级编程实例:编写守护进程