+ -
当前位置:首页 → 问答吧 → perl下多进程的进度显示

perl下多进程的进度显示

时间:2010-10-07

来源:互联网

经常遇到这样的需求, 一个父进程开启多个子进程, 每个子进程都需要做一个长时间的处理, 所以希望显示这些子进程的进度. 在网上可以找到单进程的进度显示, 但多进程的进度显示没找着.  
所以就自己想着做一个, 希望大家给点意见,要是有更好的方法的话请分享一下.
  1. #!/usr/local/bin/perl5

  2. use warnings;
  3. use strict;
  4. use Fcntl;
  5. use Term::Cap;
  6. use Parallel::ForkManager;

  7. #==============================
  8. # for terminal control
  9. #==============================
  10. my $termios = new POSIX::Termios;
  11. my $terminal = Term::Cap->Tgetent ({ TERM => undef, OSPEED => $termios->getospeed });
  12. $terminal->Trequire(qw(cm sc rc)); #check if terminal support these capabilities
  13. my $c = `clear`;
  14. print $c;

  15. #==============================
  16. # for fifo
  17. #==============================
  18. my $fpath = "myfifo";
  19. unless (-p $fpath) {
  20.     if (-e _) {
  21.         die "$fpath is something unknow\n";
  22.     }
  23.     else {
  24.         require POSIX;
  25.         POSIX::mkfifo($fpath, 0666) or die "can not mknod $fpath: $!";
  26.         print "$0: created $fpath as a named pipe\n";
  27.     }
  28. }
  29. else {
  30.     print "$0: named pipe $fpath exists\n";
  31. }


  32. #==============================
  33. # for parallel processes
  34. #==============================
  35. my @names;
  36. push @names, "p$_" foreach 0..5;
  37. my $childs;
  38. $childs->{$_} = {total=>1, processed=>0, name => $names[$_]} foreach(0.. $#names);
  39. my $remain_child_process = scalar @names;

  40. $SIG{PIPE} = sub {
  41.     -- $remain_child_process;
  42.     print STDERR "pipe broken\n";
  43. };


  44. #==============================
  45. # main program
  46. #==============================
  47. my $now = time;
  48. my $pm =  new Parallel::ForkManager(scalar @names);
  49. foreach my $child ( 0 .. $#names ) {
  50.     my $pid = $pm->start($names[$child]) and next;
  51.     print "This is $names[$child], Child number $child: $\n";
  52.     work($child);
  53.     $pm->finish($child); # pass an exit code to finish
  54. }
  55. print "Waiting for Children...\n";
  56. show_progress();
  57. $pm->wait_all_children;
  58. $now = time - $now;
  59. printf("\n\nTotal run time: %02d:%02d:%02d\n\n", int($now / 3600), int(($now % 3600) / 60), int($now % 60));
  60. print "Everybody done!\n";


  61. #==============================
  62. # real work of child process
  63. #==============================
  64. sub work {
  65.     my $child = shift;

  66.     my $total = int(rand(20)) + 5;
  67.     foreach (1..$total) {
  68.         select(undef, undef, undef, 0.2);
  69.         sysopen (FIFO_W, $fpath, O_WRONLY) or die "can't write $fpath: $!";
  70.         print FIFO_W "child:$child,processed:$_,total:$total\n";
  71.         close FIFO_W;
  72.     }

  73.     sysopen (FIFO_W, $fpath, O_WRONLY) or die "can't write $fpath: $!";
  74.     print FIFO_W "$child over\n";
  75.     close FIFO_W;
  76. }


  77. #==================================================
  78. # receive progress data from child and display them
  79. #==================================================
  80. sub show_progress {
  81.     while ($remain_child_process) {
  82.         die "Pipe file disappeared" unless -p $fpath;
  83.         sysopen (FIFO_R, $fpath, O_RDONLY) or die "can't read $fpath: $!";
  84.         while(my $m = <FIFO_R>) {
  85.             if ($m =~ m/over/) {
  86.                 -- $remain_child_process;
  87.             }
  88.             else {
  89.                 #print $m;
  90.                 my ($child, $processed, $total) = $m =~ m/child:(\w+),processed:(\d+),total:(\d+)/;
  91.                 $childs->{$child}->{processed} = $processed;
  92.                 $childs->{$child}->{total} = $total;
  93.                 proc_bar($childs);
  94.             }
  95.         }
  96.         close FIFO_R;
  97.     }
  98.     $terminal->Tgoto('cm', 0, 5+2*@names, *STDOUT); #move cursor to bottom of screen
  99. }

  100. #=====================================
  101. # indicate the progress of comparation
  102. #=====================================
  103. sub proc_bar{
  104.     my $childs = shift;
  105.     local $| = 1;

  106.     $terminal->Tgoto('sc', undef, undef, *STDOUT); #save cursor
  107.     for my $c (sort keys %$childs) {
  108.         my $i = $childs->{$c}->{processed};
  109.         my $n = $childs->{$c}->{total};
  110.         my $name = $childs->{$c}->{name};
  111.         print "\r\033[36mchild: $c($name) [\033[33m".("#" x int(($i/$n)*50)).(" " x (50 - int(($i/$n)*50)))."\033[36m]";
  112.         printf("%2.1f%%\033[0m\n",$i/$n*100);
  113.     }
  114.     $terminal->Tgoto('rc', undef, undef, *STDOUT); #restore cursor

  115.     local $| = 0;
  116. }
复制代码

作者: hp_truth   发布时间: 2010-10-07

支持一下,慢慢看~

作者: x9x9   发布时间: 2010-10-07