在Perl中如何派生多进程 -- fork函数

这个函数当前在学校没有搞懂, 刚从学校出来时也没搞懂, 不会用他来写多线程程序. 今天有人问我在Perl中如何进行多进程编程, 去Google了一把, 发现境界好象比以前高了, 因为感觉上懂了一些了. 下面是写的一个例子:
#!/usr/bin/perl
#

my $pid = fork();

if (!defined($pid))
{
   print ("Fork process failured!/n");
   exit();
}

if ($pid) 
{
     # This is the child process.
     sleep(1);
     print ("exit child after 10 seconds wait!/n");
     exit();
}
else
{
     # This is the parent process.
     print ("exit parent!/n");
}

    毕业后的这么多年中, 只有用Java来写过多线程序, 不过它可没有fork函数, 但感觉上, 他们也没有什么区别. 看来可以为refresh_mysql.pl角本增加并行执行支持了. cool!

 perl 语言编程实例-多进程篇[转]

  作者:horsley

perl 语言编程实例-多进程篇

perl 语言是一种非常强大的脚本语言,其应用遍及系统维护,CGI,数据库编程。
以下是我遇到的一个具体问题,应用perl获得圆满解决。

问题提出:
某数据库应用。需要检索一批数据(A表,数据量12万左右)。对该批数据
将进行逐一核对,期间将关联三个千万级的表(C,D,E表,分别有近亿条数据),
并将检索状态插入一张新表(F)。

传统解决方案:
编写存储过程。打开一个cursor,对A表遍历,逐一检索C,D,E表。
判断状态写入新表。编程过程十分简单,顺利完成。但执行时效率低下,耗时在
8小时左右,不能满足要求。

分析:
C,D,E表建有极其完备的索引。对单条数据检索极其快速。同时执行时主机CPU


内存等资源十分空闲。查询单条记录耗时:8×3600/12万=0.24秒,也是在合理的

范围。
同时主机数据库在业务高峰期时可以支持500-600用户同时登陆(telnet方式)。

以上
说明性能瓶颈不在主机,数据库上。

结论:以上所有都合情合理,采用单进程方式无法进一步提高性能。为提高速度,

只能
采用多进程。


快速构造原型:

原型一:
#!/usr/bin/perl

my $maxchild=20;
foreach $item (1..500) {
while ( `ps -ef|grep $0|wc -l` > $maxchild) { select undef,undef,undef,0.1; };
if ($PID=fork()){
print "Starting Sub_Process PID/n";
} else {
print "I will handle data item/n";
sleep 1;
exit 1;
};
}

执行以上,正常,子进程控制在20。

以上述脚本为基础,添加数据库部分:

#!/usr/bin/perl

use DBI;


my $dbh=DBI->connect(...);
my $sth=$dbh->prepare(qq/select * from A/);
$sth->execute();
$sth->bind_column(undef,.....);

while ($sth->fetch()) {
while ( `ps -ef|grep $0|wc -l` > $maxchild) { select undef,undef,undef,0.1; };
if ($PID=fork()) {
print "Starting Sub_Process PID/n";
} else {
query(B,C,D); #执行数据库操作
insert(E);
exit 1;
}
}
$sth->finish();
$dbh->disconnect();

确保无语法错误,执行。处理一两条数据后脚本报错,中断。具体错误略。

分析:程序框架没错,但是在fork子进程时,$dbh同时被子进程继承,导致该数据

库连接反复使用。
由于数据库底层的某种原因,对该种操作是不允许的。结论:以上简单的多进程方

式不可行。数据库
连接部分必须同 fork 分离。

######################################

考虑很久,设计如下原型:将打开A表的cursor单独提出,结果传给另外一个进程


12万数据较大,作为参数传递似乎不妥,考虑利用管道通信。



原型二:
############################

分成 getdata,setdata两个程序。首先建立管道 : mknod data.pipe p

cat getdata:

#!/usr/bin/perl

use DBI;
open(DATAPIPE,">./data.pipe") or die "$!/n";

my $dbh=DBI->connect(...);
my $sth=$dbh->prepare(qq/select * from A/);
$sth->execute();
$sth->bind_column(undef,.....);

while ($sth->fetch()) {
print DATAPIPE data.....;
}
close(DATAPIPE);

######################

cat setdata:

#!/usr/bin/perl
use DBI;
open(DATAPIPE,"<./data.pipe") or die "$!/n";

my $pipecount=0;
my $maxlines=2000;
my @lines=();

while($record=<DATAPIPE>) {
$pipecount++;
push @lines,$record;

unless ($pipecount % $maxlines) {
if ($PID=fork()){
print "Starting Sub_Process:$PID/n";
@lines=();
}else{
my $dbh=DBI->connect(...);
foreach (@lines) {
handle_data($_);
}
$dbh->disconnect();
exit 1;
}
}
}

my $dbh=DBI->connect(...);
foreach (@lines) {
handle_data($_);
}

$dbh->disconnect();

以上脚本运行正常,执行时启动:12万/$maxlines= 60个子进程。
处理完所有数据耗时在 10分钟左右,效率提高几十倍。

脚本执行方式:./getdata&./setdata
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值