基于名字自动发布之多进程(3)
项目地址: https://gitee.com/lookingdreamer/RexDeploy_v1
流程图
为什么选择多进程?
随着应用越来越多,单进程的运行已经严重的拖慢了速度.所以多进程就应运而生了.为什么不是多线程?因为rex本身的框架都是采用的多进程.且多进程相对多线程来说要稳定得多.项目本身也去尝试了多线程,但在兼容性上出现了问题.索性就全部按照多进程去设计和开发.
多进程构建思路
-
日常生活的比喻
假设商店最大容纳人数为5个人,一共有12个人.只能等前面5个人进去出来之后,后面的5个人才能进入,不足5个人的全部进去
-
转换为数学问题
将12个人编号为0到12号
#!/bin/perl
my ($start,$maxchild,$max,%hash_pids) = (0,5,12) ;
for(my $g=0; $g < $max ;){
$startIndex = $g ;
$endIndex = $g + $maxchild;
if($endIndex > $max){
$endIndex = $max;
}
$start = $start + 1 ;
print("\r\n开始第$start次并发控制:($startIndex - $endIndex) \r\n");
for($i=$startIndex;$i<$endIndex;$i++){
select(undef, undef, undef, 0.25);
my $child=fork();
if($child){
print("\r\n父进程PID:$$ 子进程PID:$child\r\n");
$hash_pids{$child} = $child;
}else{
# 在子进程中执行相关动作
print("开始执行子进程,进程序号:$i \r\n");
sleep(5);
print("结束执行子进程,进程序号:$i \r\n");
exit 0;
}
}
#收割并等待子进程完成
while (scalar keys %hash_pids) {
my $kid = waitpid(-1, WNOHANG);
if ($kid and exists $hash_pids{$kid}) {
delete $hash_pids{$kid};
}
}
print("结束第$start次并发控制:($startIndex - $endIndex) \r\n");
$g = $g + $maxchild;
}
- 转换到关键词上
比如我传名字关键词test1,test3,test4,abc,cde….,因为每个应用的名字是唯一的,我将名字添加到一个索引数组中 如上0-5对应就是索引数组的第1个到第5个,意味着第一次执行前5个名字的服务
my @ks = split(/ /, $k);
-
关键点
利用系统fork()创建多进程; 利用waitpid无阻塞的模式收割进程waitpid(-1, WNOHANG); 利用hash保存进程id
-
多进程间通讯
多进程间通讯一般分为消息队列、共享内存段以及信号量3种方式.通常情况下共享内存段和信号配合使用.在我的项目主要是通过IPC::Shareable
模块来实现进程间的数据共享
use IPC::Shareable;
......
my @shared;
my $mainProces = $$;
#创建信号
my $ipch = tie @shared, 'IPC::Shareable',
"foco",
{ create => 1,
exclusive => 'no',
mode => 0666,
size => 1024*512,
# destroy => 'yes',
};
......
my $single = {"mainProcess"=>"$mainProces","data"=>$runres} ;
#持锁
$ipch->shlock;
#保存数据到全局内存
push @shared, $single ;
#解锁
$ipch->shunlock;
- 获取当前主进程开辟的子进程的所有数据
保存到全局内存中的数组变量@shared,有可能含有其他主进程创建的子进程.所以在取出当前进程创建的子进程数据,我们需要做1个区分.因为在保存数据的时候,我们把当前的主进程ID也保存进去了.只要内存数据的数组元素的主进程PID等于主进程就是该进程创建的子进程数据.如下
......
my @mainShared;
my $u = 0 ;
my @deleteArray;
Rex::Logger::info("当前全局内存存储变量数量: $allCount");
for (my $var = 0; $var < $allCount; $var++) {
my $process = $shared[$var]->{"mainProcess"};
if ( "$process" eq "$mainProces" ) {
$u = $u + 1;
push @mainShared,$shared[$var] ;
push @deleteArray,$var;
}
}
- 不足点
创建和消亡进程的时候,对系统带来一定的开销.同时也会频繁的切换CPU.由于对系统进程的并发的数量没有限制,对系统来说并不是很好控制和友好.不知道perl多进程是否可以引入多进程池.提前初始一部分线程给程序,然后在分发线程给程序,这样对CPU的资源以及进程的控制也能达到最大效率化.
来源:oschina
链接:https://my.oschina.net/u/1452345/blog/1931253