perl 語(yǔ)言編程實(shí)例-多進(jìn)程篇
創(chuàng )建:2005-10-27 22:03:38
作者:Unlinux
來(lái)自: http://www.Unlinux.com
作者:horsley
perl 語(yǔ)言編程實(shí)例-多進(jìn)程篇
perl 語(yǔ)言是一種非常強大的腳本語(yǔ)言,其應用遍及系統維護,CGI,數據庫編程。
以下是我遇到的一個(gè)具體問(wèn)題,應用perl獲得圓滿(mǎn)解決。
問(wèn)題提出:
某數據庫應用。需要檢索一批數據(A表,數據量12萬(wàn)左右)。對該批數據
將進(jìn)行逐一核對,期間將關(guān)聯(lián)三個(gè)千萬(wàn)級的表(C,D,E表,分別有近億條數據),
并將檢索狀態(tài)插入一張新表(F)。
傳統解決方案:
編寫(xiě)存儲過(guò)程。打開(kāi)一個(gè)cursor,對A表遍歷,逐一檢索C,D,E表。
判斷狀態(tài)寫(xiě)入新表。編程過(guò)程十分簡(jiǎn)單,順利完成。但執行時(shí)效率低下,耗時(shí)在
8小時(shí)左右,不能滿(mǎn)足要求。
分析:
C,D,E表建有極其完備的索引。對單條數據檢索極其快速。同時(shí)執行時(shí)主機CPU
,
內存等資源十分空閑。查詢(xún)單條記錄耗時(shí):8×3600/12萬(wàn)=0.24秒,也是在合理的
范圍。
同時(shí)主機數據庫在業(yè)務(wù)高峰期時(shí)可以支持500-600用戶(hù)同時(shí)登陸(telnet方式)。
以上
說(shuō)明性能瓶頸不在主機,數據庫上。
結論:以上所有都合情合理,采用單進(jìn)程方式無(wú)法進(jìn)一步提高性能。為提高速度,
只能
采用多進(jìn)程。
快速構造原型:
原型一:
#!/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:$PIDn";
} else {
print "I will handle data:$itemn";
sleep 1;
exit 1;
};
}
執行以上,正常,子進(jìn)程控制在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:$PIDn";
} else {
query(B,C,D); #執行數據庫操作
insert(E);
exit 1;
}
}
$sth->finish();
$dbh->disconnect();
確保無(wú)語(yǔ)法錯誤,執行。處理一兩條數據后腳本報錯,中斷。具體錯誤略。
分析:程序框架沒(méi)錯,但是在fork子進(jìn)程時(shí),$dbh同時(shí)被子進(jìn)程繼承,導致該數據
庫連接反復使用。
由于數據庫底層的某種原因,對該種操作是不允許的。結論:以上簡(jiǎn)單的多進(jìn)程方
式不可行。數據庫
連接部分必須同 fork 分離。
######################################
考慮很久,設計如下原型:將打開(kāi)A表的cursor單獨提出,結果傳給另外一個(gè)進(jìn)程
。
12萬(wàn)數據較大,作為參數傳遞似乎不妥,考慮利用管道通信。
原型二:
############################
分成 getdata,setdata兩個(gè)程序。首先建立管道 : 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:$PIDn";
@lines=();
}else{
my $dbh=DBI->connect(...);
foreach (@lines) {
handle_data($_);
}
$dbh->disconnect();
exit 1;
}
}
}
my $dbh=DBI->connect(...);
foreach (@lines) {
handle_data($_);
}
$dbh->disconnect();
以上腳本運行正常,執行時(shí)啟動(dòng):12萬(wàn)/$maxlines= 60個(gè)子進(jìn)程。
處理完所有數據耗時(shí)在 10分鐘左右,效率提高幾十倍。
腳本執行方式:./getdata&./setdata
轉載自:http://www.unlinux.com/doc/perl/20051027/4153.html
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。