php多进程编程二
来源:互联网 发布:淘宝new balance 编辑:程序博客网 时间:2024/06/05 14:46
php在pcntl_fork()后生成的子进程(通常为僵尸进程)必须由pcntl_waitpid()函数进行资源释放。但在pcntl_waitpid()不一定释放的就是当前运行的进程,也可能是过去生成的僵尸进程(没有释放);也可能是并发时其它访问者的僵尸进程。但可以 使用posix_kill($cid, SIGTERM)在子进程结束时杀掉它。
子进程会自动复制父进程空间里的变量。
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{
// 不支持多进程处理时的代码在这里
}
//.....
?>
如果不需要阻塞进程,而又想得到子进程的退出状态,则可以注释掉pcntl_wait($status)语句,或写成:
<?php
pcntl_wait($status,1);
//或
pcntl_wait($status, WNOHANG);
在上面的代码中,如果父进程退出(使用exit函数退出或redirect),则会导致子进程成为僵尸进程(会交给init进程控制),子进程不再执行。
僵 尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程.(zombie)进程。任何进程在退出前(使用exit退出)都会变成 僵尸进程(用于保存进程的状态等信息),然后由init进程接管。如果不及时回收僵尸进程,那么它在系统中就会占用一个进程表项,如果这种僵尸进程过多, 最后系统就没有可以用的进程表项,于是也无法再运行其它的程序。
预防僵尸进程有以下几种方法:
//.....
//需要安装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{
// 不支持多进程处理时的代码在这里
}
//.....
?>
怎样产生僵尸进程的
一 个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它 的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已 经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵 尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程 结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但 是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的 阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是”Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。
如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。
另外,还可以写一个php文件,然后在以后台形式来运行它,例如:
<?php
//Action代码
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('/');
}
?>
子进程会自动复制父进
PHP多进程编程示例
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
//.....
//需要安装pcnt
if(function_e
//生成子进程
$pid = pcntl_fork
if($pid== -1){
die('could not fork');
}else{
if($pid){
$status =0;
//阻塞父进程,直到
pcntl_wait
// parent proc code
exit;
}else{
// child proc code
//结束当前子进程,
if(function_e
posix_kill
}else{
system('kill -9'.getmypid());
}
exit;
}
}
}else{
// 不支持多进程处理时的
}
//.....
?>
如果不需要阻塞进程,
<?php
pcntl_wait
//或
pcntl_wait
在上面的代码中,如果
僵 尸进程是指的父进程已
预防僵尸进程有以下几
- 父 进程通过wait和w
aitpid等函数使 其等待子进程结束,然 后再执行父进程中的代 码,这会导致父进程挂 起。上面的代码就是使 用这种方式实现的,但 在WEB环境下,它不适 合子进程需要长时间运 行的情况(会导致超时 )。使用wait和w aitpid方法使父 进程自动回收其僵尸子 进程(根据子进程的返 回状 态),waitpid 用于临控指定子进程, wait是对于所有子 进程而言。 - 如果父进程很忙,那么
可以用signal函 数为SIGCHLD安 装handler,因 为子进程结束后,父进 程会收到该信号,可以 在handler中调 用wait回收 - 如果父进程不关心子进
程什么时候结束,那么 可以用signal( SIGCHLD, SIG_IGN)通知 内核,自己对子进程的 结束不感兴趣,那么子 进程结束后,内核会回 收,并不再给父进程发 送信号,例如:pcn tl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
//....code - 还有一个技巧,就是f
ork两次,父进程f ork一个子进程,然 后继续工作,子进程再 fork一个孙进程后 退出,那么孙进程被i nit接管,孙进程结 束后,init会回收 。不过子进程的回收还 要自己做。下面是一个 例子: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()过程中,假 设子进程结束时父进程 仍存在,而父进程fo rk()之前既没安装 SIGCHLD信号处 理函数调用waitpid()等 待子进程结束,又没有 显式忽略该信号,则子 进程成为僵尸进程,无 法正常结束,此时即使 是root身份kil l-9也不能杀死僵尸 进 程。补救办法是杀死僵 尸进程的父进程(僵尸 进程的父进程必然存在 ),僵尸进程成为”孤 儿进程”,过继给1号 进程init,ini t会定期调用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<?php
//.....
//需要安装pcnt
if(function_e
//生成第一个子进程
$pid = pcntl_fork
if($pid== -1){
//子进程fork失
die('could not fork');
}else{
if($pid){
//父进程code
sleep(5); //等待5秒
exit(0);//或$this->
}else{
//第一个子进程co
//产生孙进程
if(($gpid= pcntl_fork
//孙进程产生失败
die('could not fork');
}elseif($gpid> 0){
//第一个子进程co
$status =0;
$status = pcntl_wait
if($status! = 0) file_put_c
//得到父进程id
//$ppid = posix_getp
//得到子进程id:
//kill掉子进程
//posix_ki
exit(0);
}else{//即$gpid == 0
//孙进程code
//....
//结束孙进程(即当
if(function_e
posix_kill
}else{
system('kill -9'.getmypid());
}
exit(0);
}
}
}
}else{
// 不支持多进程处理时的
}
//.....
?>
怎样产生僵尸进程的
一 个进程在调用exit
任何一个子进程(in
如果父进程在子进程结
另外,还可以写一个p
<?php
//Action代码
public function createActi
//....
//将args替换成
system('php -f insertLarg
$this->redirect('/');
}
?>
然后在insertL
如果是在终端运行ph
<?php
//Action代码
public function createActi
//....
//将args替换成
system('nohup php -f insertLarg
$this->redirect('/');
}
?>
- php多进程编程二
- PHP实现系统编程(二) --- 多进程编程介绍及孤儿进程、僵尸进程
- PHP多进程编程
- PHP多进程编程
- PHP多进程编程
- PHP多进程编程
- php 多进程编程
- php 多进程编程
- PHP多进程编程一
- PHP多进程编程总结
- php多进程编程一
- 服务器端PHP多进程编程
- PHP多进程编程实例
- PHP多进程编程实例
- PHP多进程编程实例
- PHP多进程编程实例
- PHP多进程编程初步
- 关于php多进程编程
- ARM 反汇编的查看
- Image 对象
- oracle数据库存储结构体系理解
- Android 签名详解
- 【Tech-Android-Jni】Jni小精髓
- php多进程编程二
- Error处理:Java switch case 报错:case expressions must be constant expressions
- java的map
- 当ArcGIS遇到Netezza
- rails number_to_currency将数字转换为当前区域下的货币表示
- 提高MySQL在高并发情况下的负载
- VC++中GDI对象的释放问题
- LINUX web服务器首次被攻击(PHP木马怎么被挂进来的)解决思路
- Prototype与JQuery对比