Perl多进程的用户接口是fork()函数以及对系统fork函数封装的一些module。我们在使用Perl语言编程时,如果一个任务的某一个段可以
或者需要并发很多执行,那么我们就会使用Perl多进程编程,例如同时向数据库递交多个记录的查询,同时完成多个系统信息的收集等等。
Perl的Perl多进程是这样实现的:主进程每fork一个子进程,会把当前(主进程的)内存空间的所有变量都复制一份传到新的进程里面,达到数据共享的目的。此外,主进程和子进程可以通过信号、管道等来通信。
内存空间独享也造就了Perl多进程不可避免的劣势:资源负荷以及通信复杂,对于Perl来说,每个子进程都可以看作主进程的拷贝,这多少有些内存浪费,
而且主进程的关键变量如果是“浅复制”到子进程的话,将会带来一些意想不到的错误。另外,进程的创建和回收会带来许多额外的负载,因此应当尽量避免频繁地
创建进程。
Perl多进程之间的通信方式有socket,管道,信号量等。在Linux平台上,对于进程间大量信息的交互情况,最常用的是文件;这在用户空间进程和系统内核空间进程之间的通信中的最为常用。
- our@cmd=("./apcon_2052.exp119.11.217.27A15B15",
- "./apcon_2058.exp119.11.217.65adminteamw0rkA05A06",
- "./apcon_2052.exp119.11.217.27B09D09");
- our$zombies=0;
- our$kid_proc_num=0;
-
- $SIG{CHLD}=sub{$zombies++};
-
- for(my$i=0;$i<@cmd;$i++){
- my$pid=fork();
- if(!defined($pid)){exit1;}
- unless($pid){
- system"$cmd[$i]";
- exit0;
- }
- $kid_proc_num++;
- }
-
- while(1){
- if($zombies>0){
- $zombies=0;
- my$collect;
- while(($collect=waitpid(-1,WNOHANG))>0){
- $kid_proc_num--;
- }
- }
- if($kid_proc_num==0){last;}
- else{next;}
- }
以上的代码采用多进程方式同时处理了对3个测试设备的配置操作,然后主进程等待所有配置操作完成,再进行后续的测试。
=============================================================================================
如果我们需要执行一些各异的小任务,他们可能数量较多,但生存周期都比较短,或者他们可能共享大量数据,只有小部分的变量是自身的。这个时候,很自然就想到了多线程。
线程是一个单一的执行流程,它是所有程序执行过程中最小的控制单位,即能被 CPU
所调度的最小任务单元。线程与进程之间既有联系,又完全不同。简单地说,一个线程必然属于某一个进程,而一个进程包含至少一个或者多个线程。早期的计算机
系统一次只能运行一个程序,因此,当有多个程序需要执行的时候,唯一的办法就是让它们排成队,按顺序串行执行。进程的出现打破了这种格局,CPU
资源按时间片被分割开来,分配给不同的进程使用。这样一来,从微观上看进程的执行虽然仍是串行的,但是从宏观上看,不同的程序已经是在并行执行了。如果我
们把同样的思想运用到进程上,很自然地就会把进程再细分成更小的执行单位,即线程。由于一个进程又往往需要同时执行多个类似的任务,因此这些被细分的线程
之间可以共享相同的代码段,数据段和文件句柄等资源。有了进程,我们可以在一台单 CPU 计算机系统上同时运行 Firefox 和
Microsoft Office Word 等多个程序;有了线程,我们可以使 Firefox 在不同的标签里同时加载多个不同的页面,在
Office Word 里编辑文档的同时进行语法错误检查。因此,线程给我们带来了更高的 CPU
利用率、更快速的程序响应、更经济地资源使用方式和对多 CPU 的体系结构更良好的适应性。
Perl的threads模块提供的多线程,应用于我们经典的多线程编程例如SocketServer编程、硬件驱动或者适配层编程十分有效,然而对于非线程安全的一些函数或者模块调用就无能为力了,会导致不可预知的错误或者主进程的吊死、崩溃。
perl的多线程实例:
涉及语言:Perl
所用模块:threads
模块中的方法: threads->create(),
创建一个新线程;threads->join(),
收割已经创建的线程;threads->list(threads::all),
返回所有已经创建的线程;threads->is_joinable(),
返回目标线程是否已经完成,等待join。
- use threads; #声明模块
- use warnings;use strict;
- print localtime(time),"\n"; #输出系统时间;
- my $j=0;
- my $thread;
- while()
- {
- last if($j>=10);#这里控制一下任务数量,共10个;
- #控制创建的线程数,这里是5,scalar函数返回列表threads->list()元素的个数;
- while(scalar(threads->list())<5)
- { $j++; #创建一个线程,这个线程其实就是调用(引用)函数“ss”; #函数‘ss’包含两个参数($j和$j);
- threads->new(\&ss,$j,$j);
- }
- foreach $thread(threads->list(threads::all))
- { if($thread->is_joinable()) #判断线程是否运行完成;
- { $thread->join();
- #输出中间结果;
- print scalar(threads->list()),"\t$j\t",localtime(time),"\n";
- }
- }
- }
- #join掉剩下的线程(因为在while中当j=10时,还有4个线程正在运行,但是此时程序将退出while循,所以在这里需要额外程序join掉剩下的4个线程)
- foreach $thread(threads->list(threads::all))
- { $thread->join();
- print scalar(threads->list()),"\t$j\t",localtime(time),"\n";
- }
- #输出程序结束的时间,和程序开始运行时间比较,看程序运行性能;
- print localtime(time),"\n";
- #下面就是每个线程引用的函数;
- sub ss()
- { my ($t,$s)=@_;
- sleep($t); #sleep函数,睡觉;以秒为单位;
- print "$s\t";
- }
运行过程
简要描述一下程序运行过程,以便更深入理解多线程的概念。
程序共要运行10个任务,第一个任务的作用是暂停程序1s(sleep(1));第二个任务是暂停程序2s(sleep(2));以此类推,第十个任务是暂停程序10s;
时间(s) 任务
0 1,2,3,4,5(程序初始,5个线程同时运行,需要时间最长的是线程5(5s))
1 2,3,4,5,6(经过1s后,第一个任务已经完成,被join掉,同时添加新任务6)
2 3,4,5,6,7(同上)
3 4,5,6,7,8
4 5,6,7,8,9
5 6,7,8,9,10
7-end join所有剩下的线程(所有任务都已经添加,程序中while循环退出)
方法$thread->is_joinable()的作用
前面已经说了,这个方法是用来判断线程是否已经运行完成,处于等待join的状态。当需要处理多个任务,但这些任务完成需要的时间又不一样时,这个方法就显得特别重要。
最佳的方法就是判断线程是否可以被join。如上面的程序所写的。这样可以保证程序运行过程中始终是5个线程,最大化的利用CPU资源。
阅读(5973) | 评论(0) | 转发(1) |