Chinaunix首页 | 论坛 | 博客
  • 博客访问: 156510
  • 博文数量: 42
  • 博客积分: 972
  • 博客等级: 准尉
  • 技术积分: 382
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-17 10:59
文章分类

全部博文(42)

文章存档

2014年(2)

2013年(5)

2012年(35)

我的朋友

分类: Python/Ruby

2012-11-22 13:33:29

Perl多进程的用户接口是fork()函数以及对系统fork函数封装的一些module。我们在使用Perl语言编程时,如果一个任务的某一个段可以 或者需要并发很多执行,那么我们就会使用Perl多进程编程,例如同时向数据库递交多个记录的查询,同时完成多个系统信息的收集等等。

Perl的Perl多进程是这样实现的:主进程每fork一个子进程,会把当前(主进程的)内存空间的所有变量都复制一份传到新的进程里面,达到数据共享的目的。此外,主进程和子进程可以通过信号、管道等来通信。

内存空间独享也造就了Perl多进程不可避免的劣势:资源负荷以及通信复杂,对于Perl来说,每个子进程都可以看作主进程的拷贝,这多少有些内存浪费, 而且主进程的关键变量如果是“浅复制”到子进程的话,将会带来一些意想不到的错误。另外,进程的创建和回收会带来许多额外的负载,因此应当尽量避免频繁地 创建进程。

Perl多进程之间的通信方式有socket,管道,信号量等。在Linux平台上,对于进程间大量信息的交互情况,最常用的是文件;这在用户空间进程和系统内核空间进程之间的通信中的最为常用。


点击(此处)折叠或打开

  1. our@cmd=("./apcon_2052.exp119.11.217.27A15B15",
  2. "./apcon_2058.exp119.11.217.65adminteamw0rkA05A06",
  3. "./apcon_2052.exp119.11.217.27B09D09");
  4. our$zombies=0;
  5. our$kid_proc_num=0;

  6. $SIG{CHLD}=sub{$zombies++};

  7. for(my$i=0;$i<@cmd;$i++){
  8. my$pid=fork();
  9. if(!defined($pid)){exit1;}
  10. unless($pid){
  11. system"$cmd[$i]";
  12. exit0;
  13. }
  14. $kid_proc_num++;
  15. }

  16. while(1){
  17. if($zombies>0){
  18. $zombies=0;
  19. my$collect;
  20. while(($collect=waitpid(-1,WNOHANG))>0){
  21. $kid_proc_num--;
  22. }
  23. }
  24. if($kid_proc_num==0){last;}
  25. else{next;}
  26. }
以上的代码采用多进程方式同时处理了对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。


点击(此处)折叠或打开

  1. use threads; #声明模块
  2. use warnings;use strict;
  3. print localtime(time),"\n"; #输出系统时间;
  4. my $j=0;
  5. my $thread;
  6. while()
  7. {
  8. last if($j>=10);#这里控制一下任务数量,共10个;
  9. #控制创建的线程数,这里是5,scalar函数返回列表threads->list()元素的个数;
  10. while(scalar(threads->list())<5)
  11. { $j++; #创建一个线程,这个线程其实就是调用(引用)函数“ss”; #函数‘ss’包含两个参数($j和$j);
  12. threads->new(\&ss,$j,$j);
  13. }
  14. foreach $thread(threads->list(threads::all))
  15. { if($thread->is_joinable()) #判断线程是否运行完成;
  16. { $thread->join();
  17. #输出中间结果;
  18. print scalar(threads->list()),"\t$j\t",localtime(time),"\n";
  19. }
  20. }
  21. }
  22. #join掉剩下的线程(因为在while中当j=10时,还有4个线程正在运行,但是此时程序将退出while循,所以在这里需要额外程序join掉剩下的4个线程)
  23. foreach $thread(threads->list(threads::all))
  24. { $thread->join();
  25. print scalar(threads->list()),"\t$j\t",localtime(time),"\n";
  26. }
  27. #输出程序结束的时间,和程序开始运行时间比较,看程序运行性能;
  28. print localtime(time),"\n";
  29. #下面就是每个线程引用的函数;
  30. sub ss()
  31. { my ($t,$s)=@_;
  32. sleep($t); #sleep函数,睡觉;以秒为单位;
  33. print "$s\t";
  34. }

运行过程

简要描述一下程序运行过程,以便更深入理解多线程的概念。
程序共要运行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) |
给主人留下些什么吧!~~