免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4105 | 回复: 12

初学者提问:多进程的问题,谢谢高手解答~~~ [复制链接]

论坛徽章:
0
发表于 2010-03-21 15:17 |显示全部楼层
本帖最后由 honckly 于 2010-03-21 15:25 编辑

刚开始学习perl,最近工作中遇到一个问题,请高人耐心看完,给提出一个解决方案,小弟感激不尽

场景:需要对一个目录的所有文件的内容进行处理,如果单个处理的话,耗时较大,所以采用fork()形式

代码:由于刚学习perl编程,所以用的他人的代码块,有些地方看不太懂

这里设置最大进程数为$MAX_PID = 20,@tables里有2百个文件,也就是说循环200次

foreach (my $i=0; $i<@tables; $i++) {
          if ($pid_num < $MAX_PID) {
                $pid=fork();
                if (defined $pid) {
                        if ($pid!=0) {
                        # 父进程
                                $pid_hash->{$i}->{pid} = $pid;
                                $pid_hash->{$i}->{table} = $tables[$i];
                                $pid_hash->{$i}->{starttime} = TimeOpt::CFtime("YYYY-MM-DD hh:mm:ss");
                        }
                }
                else {
                # fork失败
                        $TRACE->trace("Cann't fork $!");
                        next;
                }
                if ($pid==0) {
                # 子进程
                        $table = $tables[$i];
                        eval{
                                &get_file_content($table, $i);
                        };
                        exit(0);
                }
                else {
                # 父进程
                        $pid_num++;
                        next;
                }
        }
        else {
                $i--;
                while (1) {
                        $TRACE->trace("Running pid num = $pid_num");
                        my $tag=0;
                        my $pid;
                        foreach my $itmp (keys %$pid_hash) {
                                $pid = $pid_hash->{$itmp}->{pid};
                                if ($pid!=0) {
                                        if (!(Fcommon::isProcAlive($pid))) {
                                                $TRACE->trace("Run Finish pid=".$pid_hash->{$itmp}->{pid}." table=".$pid_hash->{$itmp}->{table});
                                                $pid_hash->{$itmp}->{pid} = 0;
                                                $pid_num--;
                                                $tag = 1;
                                        }
                                        else {
                                                my $timeout_time = TimeOpt::GMtime($pid_hash->{$itmp}->{starttime},"+5s");
                                                my $current = TimeOpt::CFtime("YYYY-MM-DD hh:mm:ss");
                                                if ($current ge $timeout_time) {
                                                        system("kill -p $pid");
                                                        $pid_hash->{$itmp}->{pid}=0;
                                                        $pid_num--;
                                                        $tag = 1;
                                                }
                                        }
                                }
                        }
                        if ($tag==1) {
                                last;
                        }
                        sleep 2;
                }
        }
}
#守护程序
while (1) {
        my $tag = 0;
        my $pid;
        foreach my $itmp (keys %$pid_hash) {
                $pid = $pid_hash->{$itmp}->{pid};
                if ($pid!=0) {
                        if (Fcommon::isProcAlive($pid)) {
                                my $timeout_time=TimeOpt::GMtime($pid_hash->{$itmp}->{starttime},"+5s");
                                my $current=TimeOpt::CFtime("YYYY-MM-DD hh:mm:ss");
                                if ($current ge $timeout_time) {
                                        system("kill -9 $pid");
                                        $pid_hash->{$itmp}->{pid} = 0;
                                }
                                else {
                                        $tag = 1;
                                }
                        }
                        else {
                                $pid_hash->{$itmp}->{pid} = 0;
                        }
                }
        }
        if ($tag == 0) {
                last;
        }
        sleep 3;
}

exit 0;

问题:

1.子进程创建后,执行&get_file_content($table, $i);后,遇到exit(0);该进程就结束了么??

2.父进程该怎么结束(我执行这段代码后,如果不kill的话,改程序永远也执行不完,光标总在最后一行闪烁,执行用ctrl+c结束掉,但是文件已经都处理完了)?

3.下面的代码也存在这个问题,我也不知道怎么才能退出?

#!/usr/bin/perl
# test_proc_3.pl
# test multi process
# create by lianming: 2009-08-12
use strict;
use warnings;
use POSIX ":sys_wait_h";
## == number of proc ==
my $num_proc = 0;
## == number of collected ==
my $num_collect = 0;
my $collect;
## == get the child signal ==
$SIG{CHLD} = sub { $num_proc-- };
for (my $i = 0; $i < 10; $i ++) {
    ## == fork a new process ==
    my $pid = fork();
    if (!defined($pid)) {
        print "Error in fork: $!";
        exit 1;
    }
    if ($pid == 0) {
        ## == child proc ==
        print "Child $i : My pid = $$\n";
        sleep(5);
        print "Child $i : end\n";
        exit 0;
    }
    $num_proc ++;
    ## == if need to collect zombies ==
    if (($i-$num_proc-$num_collect) > 0) {
        while (($collect = waitpid(-1, WNOHANG)) > 0) {
            $num_collect ++;
        }
    }
    do {
        sleep(1);
    } until ($num_proc < 3);
}
exit 0;
$num_proc:正在活动的进程数量,控制在3个以内,所以在父进程每次fork完子进程后,都会检查这个变量,如果超出了3个,那就等一会。当父进程fork了新子进程的时候,这个数字会增加,当子进程退出以后,父进程捕获了信号,这个数字会减少。
$num_collect:已回收的进程数量,每回收一个子进程,变量加一。
$i:已经fork的进程数量。
$num_proc和$num_collect的和应该是等于$i的,如果不等于了,那就说明,有子进程需要回收了。



以上的红字儿是解释,但是为什么执行完后,光标还是不停地闪烁呢,用waitpid不是可以回收进程么??怎么才能让光标不闪烁执行完毕(专业词儿我不懂,大概就是这个意思吧)??

谢谢了,真的是刚入门,原来做.net的,对多进程一窍不通,已经看了2天了,也没啥眉目,希望大家帮助我一下吧,谢谢啦~~~~

论坛徽章:
0
发表于 2010-03-21 15:17 |显示全部楼层
对了,这个账号是我朋友的,已经发了这么多帖子了哇,我在线等

论坛徽章:
0
发表于 2010-03-21 15:45 |显示全部楼层
  1. #!/usr/bin/perl
  2. # test_proc_3.pl
  3. # test multi process
  4. # create by lianming: 2009-08-12
  5. use strict;
  6. use warnings;
  7. use POSIX ":sys_wait_h";
  8. ## == number of proc ==
  9. my $num_proc = 0;
  10. ## == number of collected ==
  11. my $num_collect = 0;
  12. my $collect;
  13. ## == get the child signal ==
  14. $SIG{CHLD} = sub { $num_proc-- };
  15. for (my $i = 0; $i < 10; $i ++) {
  16.     ## == fork a new process ==
  17.     my $pid = fork();
  18.     if (!defined($pid)) {
  19.         print "Error in fork: $!";
  20.         exit 1;
  21.     }
  22.     if ($pid == 0) {
  23.         ## == child proc ==
  24.         print "Child $i : My pid = $\n";
  25.         sleep(5);
  26.         print "Child $i : end\n";
  27.         exit 0;
  28.     }
  29.     $num_proc ++;
  30.     ## == if need to collect zombies ==
  31.     if (($i-$num_proc-$num_collect) > 0) {
  32.         while (($collect = waitpid(-1, WNOHANG)) > 0) {
  33.             $num_collect ++;
  34.         }
  35.     }
  36.     do {
  37.         sleep(1);
  38.     } until ($num_proc < 3);
  39. }
  40. exit 0;
复制代码

请高手执行一下这个,光标在最后一直闪,也不说执行完毕了,能不能告诉我我程序怎么写,他才能自动跳出

论坛徽章:
0
发表于 2010-03-21 15:58 |显示全部楼层


这人会PHP

论坛徽章:
0
发表于 2010-03-21 23:27 |显示全部楼层
帮顶,等大大解答。一般光标一直闪,就是有死循环,退不出去吧。

论坛徽章:
0
发表于 2010-03-22 09:03 |显示全部楼层
回复 5# blackmuyu


    我用exit退出了哇~~~

论坛徽章:
0
发表于 2010-03-22 10:50 |显示全部楼层
  1. #     do {
  2. #         sleep(1);
  3. #     } until ($num_proc < 3);
复制代码
死循环?

论坛徽章:
0
发表于 2010-03-22 10:57 |显示全部楼层
迷糊。。。

论坛徽章:
0
发表于 2010-03-22 14:05 |显示全部楼层
回复 7# Ray001

整个是保证最多开3个子进程,如果超出3个父进程进行回收

我也不知道理解的对不对,刚开始接触整个。。。

论坛徽章:
0
发表于 2010-03-22 14:59 |显示全部楼层
没问题阿
我这退出得好好的
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP