Perl多进程
perl作为一种解释性的语言,很受广大系统管理员的欢迎,好处么就不多说了,坏处也有不少,例如对线程的支持,就一直不咋地,所以大多数情况下,我们都需要多个进程,来帮助我们完成工作,闲话少说,上代码。
执行结果如下: # test_proc_1.pl
# create by lianming: 2009-08-12
use?strict;
use?warnings;
?
for?
(
my?
$i?=?
0;?
$i?
<?
10;?
$i?++
## == fork a new process ==
? ??
);
? ??
{
? ? ? ??
"Error in fork: $!";
? ? ? ??
1;
? ??
}
? ??
{
? ? ? ??
## == child proc ==
? ? ? ??
"Child $i : My pid = $$n";
? ? ? ??
);
? ? ? ??
"Child $i : end0;
? ??
}
? ??
1
);
这个例子就是,父进程执行一个循环,每次循环都fork一个子进程,子进程执行完以后退出,每次循环都等待1s,循环10次。 执行结果如下: Child 0 : My pid = 20499 Child 1 : My pid = 20500 Child 2 : My pid = 20501 Child 3 : My pid = 20502 Child 4 : My pid = 20503 Child 0 : end Child 5 : My pid = 20506 Child 1 : end Child 6 : My pid = 20507 Child 2 : end Child 7 : My pid = 20508 Child 3 : end Child 8 : My pid = 20509 Child 4 : end Child 9 : My pid = 20510 Child 5 : end [root@localhost /tmp] # Child 6 : end Child 7 : end Child 8 : end Child 9 : end 每个子进程耗时5s,那么执行完总共需要的是15s。 但是,这样的代码会导致一个问题,在执行的过程中,可以在另外的tty上输入ps auxf来查看当前的进程状态,会发现类似这样的东东: root 20531 0.0 0.0 8460 1704 pts/2 S+ 21:46 0:00 _ perl test_proc_1.pl root 20532 0.0 0.0 0 0 pts/2 Z+ 21:46 0:00 _ [perl]? root 20535 0.0 0.0 0 0 pts/2 Z+ 21:46 0:00 _ [perl]? root 20536 0.0 0.0 0 0 pts/2 Z+ 21:46 0:00 _ [perl]? root 20539 0.0 0.0 0 0 pts/2 Z+ 21:46 0:00 _ [perl]? root 20541 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 _ perl test_proc_1.pl root 20543 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 _ perl test_proc_1.pl root 20545 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 _ perl test_proc_1.pl root 20546 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 _ perl test_proc_1.pl root 20548 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 _ perl test_proc_1.pl 有4个进程,状态为Z,意思就是僵尸进程,而正常的程序,是不应该出现僵尸进程的。 正常情况下,子进程的退出需要做两件事情,第一,子进程exit,发出一个信号给自己的父进程,第二,父进程对子进程进行回收,如果父进程已经不存在了,那子进程会将init,也就是linux中第一个进程作为自己的父进程,init会代替它的父进程对子进程进行回收。 我们的情况就是,子进程已经调用了exit,但是父进程并没有对它进行回收,如果父进程持续fork子进程,那僵尸进程就会越来越多,越来越多,最后会导致什么后果,我就不说了。 父进程回收子进程的函数有两个: wait,和waitpid wait函数比较简单,没有任何参数,调用以后,父进程会停住,然后等待子进程返回。如果没有子进程,返回-1 waitpid有两个参数,第一个参数为要等待的子进程的pid值,另外一个是flag,一般来讲,第一个参数为-1,意思就是等待所有的子进程。调用方法如下:
$procid?=?
(
$procid?==?
{
# == child process ==
print?
(
"this line is printed firstn"
);
exit
# == parent process ==
waitpid?
(
$procid,?
"this line is printed last}
其实,最主要的是让父进程知道,什么时候才需要去回收已经退出的子进程,因为父进程也是有很多活需要忙的。 # test_proc_2.pl
# create by lianming: 2009-08-12
use?strict;
use?warnings;
use?POSIX?
":sys_wait_h";
## == number of zombies proc ==
my?
$zombies?=?
0;
my?
$collect;
## == get the child signal ==
$SIG
{CHLD
}?=?
sub?
{?
$zombies++?
};
?
}
? ??
## == if need to collect zombies ==
? ??
(
$zombies?
>?
{
? ? ? ??
while?
(
$collect?=?
waitpid
-1,WNOHANG
)?
>?
{
? ? ? ? ? ??
$zombies?--;
? ? ? ??
}
? ??
执行结果和原先一样: Child 0 : My pid = 21552 Child 1 : My pid = 21553 Child 2 : My pid = 21554 Child 3 : My pid = 21555 Child 4 : My pid = 21556 Child 0 : end Child 5 : My pid = 21558 Child 1 : end Child 6 : My pid = 21570 Child 2 : end Child 7 : My pid = 21572 Child 3 : end Child 8 : My pid = 21574 Child 4 : end Child 9 : My pid = 21575 Child 5 : end [root@localhost /tmp] # Child 6 : end Child 7 : end Child 8 : end Child 9 : end 但是ps auxf的结果就有很大差别了: root 21551 0.1 0.0 8280 2672 pts/2 S+ 22:06 0:00 _ perl test_proc_2.pl root 21558 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 _ perl test_proc_2.pl root 21570 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 _ perl test_proc_2.pl root 21572 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 _ perl test_proc_2.pl root 21574 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 _ perl test_proc_2.pl root 21575 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 _ perl test_proc_2.pl 僵尸进程不会存在了。 $SIG{CHLD} = sub { $zombies++ }; 这条语句,其实就是捕获了子进程退出的时候,向父进程发出的信号,捕获以后,就给一个变量($zombies)加1。 如果"$zombies"不为0的时候,那就说明,有子进程退出了,需要进行回收,那父进程就调用waidpid函数,进行一次回收,每回收一个子进程,就给这个变量减去1,这样当"$zombies"减为0的时候,就说明所有的僵尸进程都已经回收了。bingo! 有的时候,我们只是执行一定量的任务,只管fork就可以了,但是某些时候,我们有太多任务需要执行,要一直持续的fork好多子进程,但是我们希望把子进程的数目控制在一个范围内,比如说,我一个任务,需要有100个子进程来执行,但是我不能100个进程全部fork出去,这样太占用资源了,所以我希望把进程数量控制在10个以内,当第一个进程退出以后,我再fork第11个进程,例子如下: # test_proc_3.pl
## == number of proc ==
my?
$num_proc?=?
0;
## == number of collected ==
my?
$num_collect?=?
{?
$num_proc--?
};
}
? ??
$num_proc?++;
? ??
(
$i-
$num_proc-
$num_collect
{
? ? ? ? ? ??
$num_collect?++;
? ? ? ??
do?
);
? ??
until?
(
$num_proc?
<?
3
执行结果如下: Child 0 : My pid = 22641 Child 1 : My pid = 22642 Child 2 : My pid = 22643 Child 0 : end Child 3 : My pid = 22645 Child 1 : end Child 4 : My pid = 22647 Child 2 : end Child 5 : My pid = 22658 Child 3 : end Child 6 : My pid = 22660 Child 4 : end Child 7 : My pid = 22661 Child 5 : end Child 8 : My pid = 22663 Child 6 : end Child 9 : My pid = 22664 Child 7 : end [root@localhost /tmp] # Child 8 : end Child 9 : end 同时,看到的ps auxf的输出如下: root 22640 0.0 0.0 8116 2672 pts/2 S+ 22:28 0:00 _ perl test_proc_3.pl root 22660 0.0 0.0 0 0 pts/2 Z+ 22:29 0:00 _ [perl]? root 22661 0.0 0.0 8116 1168 pts/2 S+ 22:29 0:00 _ perl test_proc_3.pl root 22663 0.0 0.0 8116 1168 pts/2 S+ 22:29 0:00 _ perl test_proc_3.pl root 22664 0.0 0.0 8116 1168 pts/2 S+ 22:29 0:00 _ perl test_proc_3.pl 第一个子进程需要5s才能退出,如果1s执行一次fork的话,那么同时应该有5个子进程,但是本例中只有三个,那就是说实现了对进程数量的控制。 本例中定义了几个变量: $num_proc:正在活动的进程数量,控制在3个以内,所以在父进程每次fork完子进程后,都会检查这个变量,如果超出了3个,那就等一会。当父进程fork了新子进程的时候,这个数字会增加,当子进程退出以后,父进程捕获了信号,这个数字会减少。 $num_collect:已回收的进程数量,每回收一个子进程,变量加一。 $i:已经fork的进程数量。 $num_proc和$num_collect的和应该是等于$i的,如果不等于了,那就说明,有子进程需要回收了。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |