走向并行系列-perl的多线程(二)

来源:互联网 发布:淘宝森所男装sensu官网 编辑:程序博客网 时间:2024/06/08 10:12
在当今多核CPU主流的形势下,多核并行程序提供了最大话利用CPU的可能性。perl自5.6版本后开始提供ithread模块专门为perl的多线程提供技术支持。在perl的多线程一文中,我们初步探讨了perl的多线程技术。里面使用了is_joinable方法,来判断目标线程是否已经执行完成,并处于等待join的状态。程序源码如下(http://blog.sina.com.cn/s/blog_7ea1e7fc0100r61x.html):
use threads;use warnings;use strict;
print localtime(time),"\n";
my $j=0;
my $thread;
while()
   last if($j>=10);
        while(scalar(threads->list())<5)  
     {    $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";
           }
       }
}

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);      
    print "$s\t";
}
上述方法有一个极大的缺陷。如果正在执行的五个线程都没有执行完成,最外层的while循环将会一直“空转”,直到有一个线程被join掉,while循环在控制创建新的线程。这个过程中,主线程因为这个while循环的存在,会一直耗费系统资源。其实在任务管理器中可以看到,我们的程序会耗费50%的CPU(双核CPU),实际上这都耗费在了没有执行任何功能的外层while循环上。
在perl创建的线程结束时不会有任何提示,以告诉主线程说自己(从线程)已经结束。所以必须使用附加程序来判断目标线程是否已经执行完成,并立即join掉线程,以释放系统资源。但是这个判断过程及耗系统资源。正如上面的程序。
为此,在一次google了一下,感谢云舒提供的方法(http://icylife.net/yunshu/show.php?id=617),终于学会了。
---------------------------------------------------
信号量
Thread::Semaphore 包为线程提供了信号量的支持。使用信号量可以控制并行的线程数。
对象申明:
my $semaphore = Thread::Semaphore->new(5);
or my $semaphore = new Thread::Semaphore(5) 控制并行的最大线程数
对象方法:
$semaphore->down;     
获取一个信号量,之后可用的信号量减1,当$semaphore=0时,表示所有的线程都已经创建,无法获得新的信号量,并且此时主线程处于等待。直到获得新的信号量为止。
$semaphore->up;
释放一个信号量,之后可用信号量加1.当一个线程执行完毕时,调用此方法,释放一个信号量。此时 $semaphore->down方法获得信号量成功。处于等待的主线程从新唤醒,创建新的线程。
 
--------------------------------------------------------------------
收割线程
上次使用的程序收割线程时使用的是join方法,join方法的特点就是如果线程已经执行完毕,那么此时调用join方法理所当然,但是如果join调用过早,线程还没有执行完毕,主线程就会处于拥堵状态。知道从线程执行完毕,join方法完成为止。这极大的限制了程序运行的性能。
perl里面提供了另外一种收割线程的方法:detach。detach的特点是直接把从线程从主线程里面剥离,以后互不相关。当从线程执行完毕时会自动释放占有的资源。算是省心省力了。这里我们将尝试使用detach方法收割线程,并且使用信号量来控制线程的数量。
实例:
------------------------------------------------------------
use threads;
use Thread::Semaphore;
my $j=0;
my $thread;my $max_threads=5;
my $semaphore=new Thread::Semaphore($max_threads);

print localtime(time),"\n";
while()
   if($j>10)
    {    last;
    }
   
    $j=$j+1;
    #获得一个信号量;当执行的线程数为5时,获取失败,主线程等待。直到有一个线程结束,新的信号量可用。回复正常运行;
    $semaphore->down();    
        
    my $thread=threads->new(\&ss,$j,$j); #创建线程;
    $thread->detach();                #剥离线程;
}

#必须存在的部分,用在控制在主线程结束前保证所有剥离的线程已经执行完成。否则的话,当主线程结束时还有从线程没有执行完成,这时从线程将不得不被强行kill掉(皮之不存毛将焉附)。
&waitquit; 

print localtime(time),"\n";

sub ss() 
  my ($t,$s)=@_;
    sleep($t);
    print "$s\t",scalar(threads->list()),"\t$j\t",localtime(time),"\n";
    $semaphore->up();                  #当线程执行完成时,释放信号量。
}

#来源于云舒(http://icylife.net/yunshu/show.php?id=617);
sub waitquit
   print "Waiting to quit...\n";
    my $num=0;
    while($num<$max_thread)
    {    $semaphore->down();
        $num++;
        print "$num thread quit...\n";
    }
    print "All $max_thread thread quit\n";
}
------------------------------------------------
程序运行结果和前文一致。就不描述了(http://blog.sina.com.cn/s/blog_7ea1e7fc0100r61x.html)。
与上次使用的代码最大区别在于少了一个外循环用来判断从线程是否已经执行完成。极大的降低了CPU的使用率。
0 0
原创粉丝点击