内容简介:现在学习Perl的人真不多了(略微有点感触),最近想了解下Perl的多线程/多进程的使用方法,在网上查下文章想学习下,结果发现都是2-5年前写的文章了。当然以”胶水”语言著称的Perl也不太适合来写一些讲究效率的软件,毕竟速度摆着那;尤其在生信领域,常规的软件还是R/Python比较多,如果是支持多线程的软件则一般也是C++/JAVA写的整理下Perl多线程/多进程的一些个人简单的理解其实这篇文章主要是接着
现在学习 Perl 的人真不多了(略微有点感触),最近想了解下Perl的多线程/多进程的使用方法,在网上查下文章想学习下,结果发现都是2-5年前写的文章了。当然以”胶水”语言著称的Perl也不太适合来写一些讲究效率的软件,毕竟速度摆着那;尤其在生信领域,常规的软件还是R/Python比较多,如果是支持多线程的软件则一般也是C++/JAVA写的
整理下Perl多线程/多进程的一些个人简单的理解
- 当你需要对多个数据进行同步处理时,那么可以考虑用多进程/多线程
- 多进程拥有多个pid,独立占用内存,多线程的pid不独立
- 如果你只需要将各个任务独立生成结果的话,那么可以选择多进程;如果需要将各个任务的返回结果进行合并等处理的话,那么选择多线程
- 如果想用多进程,可以考虑使用fork方法(这里不展开了,因为我暂时也用不着。。。),多线程则使用Perl自带的threads模块
- 虽然网上说Perl的多线程/多进程支持并不太好,但是简单的用用还是可以的
其实这篇文章主要是接着 使用Perl/sed/awk分割大文件(测序fastq文件) 的后续,在分割fastq文件后,我需要用Perl(主要我其他语言多线程不会~~而且R也不太适合处理这个,除非用R包。。)来多线程处理下这几个分割后的文件,这样相比对整个文件处理会快上很多!!!顺便练练手
需要解决的问题:统计fastq文件下每个位置上(PE150测序的话,就是1-150位)的碱基质量分数Q(Base quality score)
我是用threads模块来进行多线程的,最初我的思路是将整个fastq文件读入后再分割成不同块放在数组中,然后再交给多线程处理,但是perl默认会将变量都copy到每个新线程上,这里会导致内存极大的浪费。所以后来考虑先将文件分割后,再使用多线程分别读入处理,这样内存使用率就很小了
PS.不知道为啥,在perl中调用awk来分割文件会比在 shell 脚本中要慢。。。所以这里我还是用perl的方法来写分割文件吧
下面是代码部分:
#!/usr/bin/perl -w use strict; use threads; use threads::shared; my $in = shift @ARGV; # 计算文件总行数 my $total_num = `wc -l < $in`; # 调用线程数(也是分割子文件数目) my $thread_counts = 4; # 每个子文件的行数 my $size = (int($total_num / ($thread_counts * 4)) + 1)*4; # 分割文件-awk写法 # `awk -v sz=$size 'BEGIN{i=1}{ print > FILENAME "." i ".tmp"; if (NR>=i*sz){close(FILENAME "." i ".tmp");i++}}' $in`; # 分割文件-perl写法 my %handles; foreach(1..$thread_counts){ my $outfile = $in.".$_.tmp"; open $handles{$_}, ">$outfile" or die; } open my $fh, $in or die; my $number = 1; while (<$fh>){ chomp; if ($. % $size != 0){ print {$handles{$number}} "$_\n"; }else{ print {$handles{$number}} "$_\n"; $number++; } } ################################################################ my @files = glob ("*.tmp"); # 开始多线程 foreach (0..$thread_counts-1){ print "Start one thread\n"; my $thr = threads -> create(\&get_func, $files[$_]); } # join各个线程的结果 my %qc; while(threads -> list()){ foreach my $t(threads -> list(threads::joinable)){ my $tmp = $t -> join(); foreach(1..150){ $qc{$_} += ${$tmp}{$_} -> {qual}; } } } unlink glob "*.tmp"; print $qc{150}/$total_num*4; # 多线程调用的子函数 sub get_func { my ($file) = @_; open my $fhsub, $file or die; my %hash_sub; while (<$fhsub>){ chomp; if ($. % 4 == 0){ my @base_qual = split //, $_; for (my $i=0; $i<=$#base_qual; $i++){ $hash_sub{$i+1} -> {qual} += int(ord($base_qual[$i])-33); } } } close $fhsub; return \%hash_sub; }
将上述代码的多线程部分整理下,Perl多线程的简单模板一般如下:
-
创建线程(一般循环创建),调用子函数以及输入相关参数
my $thr = threads -> create(\&get_func, $parameter);
也可以这样:
$threads[$i] = threads -> create(\&get_func, $parameter);
-
join线程,也就是收割创建的线程
while(threads -> list()){ foreach my $t(threads -> list(threads::joinable)){ my $tmp = $t -> join(); } }
这里的
threads -> list()
是为了将所有已经创建的线程列出(PS.如果在创建线程的时候就将线程都放在某个数组中的话,那么没必要这样了)threads -> list(threads::joinable)
相当于返回已经完成的线程的,可以等待join的那种,也可以使用threads->is_joinable()
,这个好处是:可以将一些已经完成的线程先join出来,没必要等待前一个线程完成了才能join后一个线程$t -> join()
就是收割线程的结果了,如果要处理这个结果(也就是子函数的结果),记得将其赋予某个变量 -
如果不需要join结果,那么用
threads->detach()
剥离已创建的线程(记得要将没用的线程剥离掉) -
默认下数据都是线程私有的,如果你想在每个线程中share某个变量,数组,散列及其引用,那么可以用
use threads::shared
;但是需要注意是:正确的做法是先将变量share后,再对其进行赋值处理,不然先赋值后share的话,会造成之前赋值的都没了 -
有其他需求的话,可以试试fork来多线程
Perl现在的网上资源真心没法跟 Python 比了,就这个多线程而言,Python一搜就好多资料(主要是中文哈)可以查看,但是Perl的都比较老的资料了。。。我是不是可以开始转一波Python了。。。
本文出自于 http://www.bioinfo-scrounger.com 转载请注明出处
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 多线程应用--Http请求阻塞回调处理
- MyExcel 3.7.0 发布,屏蔽多线程处理细节
- c# – 使用线程处理队列的最有效的方式
- 如何处理ASP.NET中未处理的线程异常?
- Intel 处理器又曝漏洞 TLBleed:超线程技术惹祸
- UWeb v1.2.2 发布,采用 AOP 切面和线程处理日志信息
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。