Linux并行作业执行工具GNU Parallel怎么用
本篇内容介绍了“Linux并行作业执行工具GNU Parallel怎么用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
GNU Parallel是一个shell工具,为了在一台或多台计算机上并行的执行计算任务,一个计算任务可以是一条shell命令或者一个以每一行做为输入的脚本程序。通常的输入是文件列表、主机列表、用户列表、URL列表或者表格列表;一个计算任务也可以是一个从管道读取的一条命令。
Usage:parallel[options][command[arguments]]command[arguments]](:::arguments|::::argfile(s))...cat...|parallel--pipe[options][command[arguments]]常用选项::::后面接参数::::后面接文件-j、--jobs并行任务数-N每次输入的参数数量--xargs会在一行中输入尽可能多的参数-xapply从每一个源获取一个参数(或文件一行)--header把每一行输入中的第一个值做为参数名-m表示每个job不重复输出“背景”(context)-X与-m相反,会重复输出“背景文本”-q保护后面的命令--trimlr去除参数两头的空格,只能去除空格,换行符和tab都不能去除--keep-order/-k强制使输出与参数保持顺序--keep-order/-k--tmpdir/--results都是保存文件,但是后者可以有结构的保存--delay延迟每个任务启动时间--halt终止任务--pipe该参数使得我们可以将输入(stdin)分为多块(block)--block参数可以指定每块的大小1.1 输入源
GNU Parallel的输入源支持文件、命令行和标准输入(stdin或pipe)。
#命令行单输入源[20:41sxuan@hulab~]$parallelecho:::abcde|teea.txtabcde#stdin(标准输入)作为输入源[20:42sxuan@hulab~]$cata.txt|parallelechoabcde#GNUParallel支持通过命令行指定多个输入源,它会生成所有的组合。这在某些需要组合时非常好用[20:45sxuan@hulab~]$parallelecho:::ABC:::DEF|teeb.txtADAEAFBDBEBFCDCECF#多个文件作为输入,此时多个文件中的内容也会像上面那样进行组合[20:46sxuan@hulab~]$parallel-aa.txt-ab.txtecho#stdin(标准输入)作为文件源中的一个,使用-,输出结果同上[20:52sxuan@hulab~]$cata.txt|parallel-a--ab.txtecho#可以使用::::代替-a,后面可接多个文件名[20:55sxuan@hulab~]$cata.txt|parallelecho::::-b.txt#最后,:::和::::可以同时使用,同样的输出结果也会进行组合[20:55sxuan@hulab~]$parallelecho:::ab::::b.txt
当然,若不想像上面那样进行组合,可使用--xapply
参数从每一个源获取一个参数(或文件一行),这个参数有些类似R中的函数,具有广播作用——如果其中一个输入源的长度比较短,它的值会被重复。
[20:57sxuan@hulab~]$parallel--xapplyecho:::ABC:::DEFADBECF[21:04sxuan@hulab~]$parallel--xapplyecho:::ABC:::DEFGHIADBECFAGBHCI1.2 改变参数分隔符
GNU Parallel可以通过--arg-sep
和--arg-file-sep
指定分隔符替代 ::: 或 ::::,当这两个符号被其它命令占用的时候会特别有用。
[21:18sxuan@hulab~]$parallel-k--arg-sep,,,echo,,,ab,,,cd|teec.txtacadbcbd[21:22sxuan@hulab~]$parallel--xapply--arg-file-sep,,,,echo,,,,a.txtb.txtaADbAEcAFdBDeBEaBFbCDcCEdCF1.3 改变输入分隔符
GNU Parallel默认把一行做为一个参数:使用 \n 做为参数定界符。可以使用 -d 改变:
[21:25sxuan@hulab~]$parallel-dbecho::::a.txtacde1.4 提前结束和跳过空行
GNU Parallel支持通过-E
参数指定一个值做为结束标志:
[21:26sxuan@hulab~]$parallel-Estopecho:::ABstopCDAB
GNU Parallel使用 --no-run-if-empty
来跳过空行:
[21:28sxuan@hulab~]$(echo1;echo;echo2)|parallel--no-run-if-emptyecho121.5 构建命令行
如果parallel之后没有给定命令,那么这些参数会被当做命令:
[21:29sxuan@hulab~]$parallel:::ls'echofoo'pwda.txtb.txtc.txtjianchenmypipescriptssnake_testWGS_snakefoo/home/sxuan
此外,命令还可以是一个脚本文件,一个二进制可执行文件或一个bash的函数(须用 export -f 导出函数)
[21:42sxuan@hulab~]$echo"echo\$*">s.sh[21:44sxuan@hulab~]$parallel./s.sh:::"abcf""1234"abcf12341.6 替换字符串
GNU Parallel支持多种替换字符串,默认使用 {},使用 -I 改变替换字符串符号 {}。其最常见的字符串替换包括以下几种:{.}
,去掉扩展名;{/}
,去掉路径,只保留文件名;{//}
,只保留路径;{/.}
,同时去掉路径和扩展名;{#}
,输出任务编号。同时对于每一个字符串替换都可以自己指定符号:-I
对应{}
;--extensionreplace
替换 {.}
;--basenamereplace
替换 {/}
;--dirnamereplace
替换{//}
;--basenameextensionreplace
替换 {/.}
;--seqreplace
替换 {#}
。
[22:02sxuan@hulab~]$parallelecho:::A/B.C;parallelecho{}:::A/B.C;parallel-I,,echo,,:::A/B.CA/B.CA/B.CA/B.C[22:04sxuan@hulab~]$parallelecho{.}:::A/B.C;parallel--extensionreplace,,echo,,:::A/B.CA/BA/B[22:08sxuan@hulab~]$parallelecho{/}:::A/B.C;parallel--basenamereplace,,echo,,:::A/B.CB.CB.C[22:08sxuan@hulab~]$parallelecho{//}:::A/B.C;parallel--dirnamereplace,,echo,,:::A/B.CAA[22:10sxuan@hulab~]$parallelecho{/.}:::A/B.C;parallel--basenameextensionreplace,,echo,,:::A/B.CBB[22:13sxuan@hulab~]$parallelecho{#}:::ABC;parallel--seqreplace,,echo,,:::ABC123123
同时,如果有多个输入源时,可以通过 {编号} 指定某一个输入源的参数:
[22:14sxuan@hulab~]$parallel--xapplyecho{1}and{2}:::AB:::CDAandCBandD#可以使用////.和.改变指定替换字符串[22:14sxuan@hulab~]$parallelecho/={1/}//={1//}/.={1/.}.={1.}:::A/B.CD/E.F/=B.C//=A/.=B.=A/B/=E.F//=D/.=E.=D/E#位置可以是负数,表示倒着数[22:16sxuan@hulab~]$parallelecho1={1}2={2}3={3}-1={-1}-2={-2}-3={-3}:::AB:::CD:::EF1=A2=C3=E-1=E-2=C-3=A1=A2=C3=F-1=F-2=C-3=A1=A2=D3=E-1=E-2=D-3=A1=A2=D3=F-1=F-2=D-3=A1=B2=C3=E-1=E-2=C-3=B1=B2=C3=F-1=F-2=C-3=B1=B2=D3=E-1=E-2=D-3=B1=B2=D3=F-1=F-2=D-3=B1.7 按列输入和指定参数名
使用 --header
把每一行输入中的第一个值做为参数名。
[22:17sxuan@hulab~]$parallel--xapply--header:echof1={f1}f2={f2}:::f1AB:::f2CD|teed.txtf1=Af2=Cf1=Bf2=D
使用 –colsep 把文件中的行切分为列,做为输入参数。
[22:31sxuan@hulab~]$perl-e'printf"f1\tf2\nA\tB\nC\tD\n"'>tsv-file.tsv[22:32sxuan@hulab~]$parallel--header:--colsep'\t'echof1={f1}f2={f2}::::tsv-file.tsvf1=Af2=Bf1=Cf2=D1.8 多参数
--xargs
会在一行中输入尽可能多的参数(与参数字符串长度有关),通过-s
可指定一行中参数的上限。
[09:44sxuan@hulab~]$perl-e'for(1..30000){print"$_\n"}'>num30000[09:50sxuan@hulab~]$catnum30000|parallel--xargsecho|wc-l3###这里官网给出的例子是2行,我的计算机centos7上面的结果是3行,应该跟linux版本有关[09:50sxuan@hulab~]$catnum30000|parallel--xargs-s10000echo|wc-l17
为了获得更好的并发性,GNU Parallel会在文件读取结束后再分发参数。 GNU Parallel 在读取完最后一个参数之后,才开始第二个任务,此时会把所有的参数平均分配到4个任务(如果指定了4个任务)。 第一个任务与上面使用 --xargs
的例子一样,但是第二个任务会被平均的分成4个任务,最终一共5个任务。(奇怪的是我的结果与官网教程的结果不一样)
[11:44sxuan@hulab~]$catnum30000|parallel--jobs4-mecho|wc-l6###官网教程里这里是5#10分参数分配到4个任务可以看得更清晰(这里的结果与官网一致)[11:50sxuan@hulab~]$parallel--jobs4-mecho:::{1..10}12345678910
替换字符串可以是输出字符的一部分,使用-m
参数表示每个job不重复输出“背景”(context),-X
则与-m
相反,会重复输出“背景文本”,具体通过下面几个例子进行理解:
[11:36sxuan@hulab~]$parallel--jobs4echopre-{}-post:::ABCDEFGpre-A-postpre-B-postpre-C-postpre-D-postpre-E-postpre-F-postpre-G-post[11:51sxuan@hulab~]$parallel--jobs4-mechopre-{}-post:::ABCDEFGpre-AB-postpre-CD-postpre-EF-postpre-G-post[11:57sxuan@hulab~]$parallel--jobs4-Xechopre-{}-post:::ABCDEFGpre-A-postpre-B-postpre-C-postpre-D-postpre-E-postpre-F-postpre-G-post
使用 -N
限制每行参数的个数,其中-N0
表示一次只读取一个参数,且不输入这个参数(作为计数器来使用)。
[12:04sxuan@hulab~]$parallel-N4echo1={1}2={2}3={3}:::ABCDEFGH1=A2=B3=C1=E2=F3=G[12:05sxuan@hulab~]$parallel-N0echofoo:::123foofoofoo1.9 引用
如果命令行中包含特殊字符,就需要使用引号保护起来。 perl脚本 ‘print “@ARGV\n”‘ 与linux的 echo 的功能一样。
[12:05sxuan@hulab~]$perl-e'print"@ARGV\n"'AA
使用GNU Parallel运行这条命令的时候,perl命令需要用引号包起来,也可以使用-q
保护perl命令:
[12:08sxuan@hulab~]$parallelperl-e'print"@ARGV\n"':::Thiswontwork[12:09sxuan@hulab~]$parallel-qperl-e'print"@ARGV\n"':::ThisworksThisworks[12:10sxuan@hulab~]$parallelperl-e\''print"@ARGV\n"'\':::Thisworks,tooThisworks,too1.10 去除空格
使用--trim
去除参数两头的空格:
[12:10sxuan@hulab~]$parallel--trimrechopre-{}-post:::'A'pre-A-post[12:12sxuan@hulab~]$parallel--trimlechopre-{}-post:::'A'pre-A-post[12:12sxuan@hulab~]$parallel--trimlrechopre-{}-post:::'A'pre-A-post1.11 控制输出
使用--tag
以参数做为输出前缀,使用--tagstring
修改输出前缀:
[12:17sxuan@hulab~]$parallel--tagechofoo-{}:::ABCAfoo-ABfoo-BCfoo-C[12:19sxuan@hulab~]$parallel--tagstring{}-barechofoo-{}:::ABCA-barfoo-AB-barfoo-BC-barfoo-C
--dryrun
作用类似于echo:
[12:19sxuan@hulab~]$parallel--dryrunecho{}:::ABCechoAechoBechoC[12:20sxuan@hulab~]$parallelecho{}:::ABCABC
--verbose
则在运行之前先打印命令:
[12:21sxuan@hulab~]$parallel--verboseecho{}:::ABCechoAechoBechoCABC
一般来说,GNU Parallel 会延迟输出,直到一组命令执行完成。使用--ungroup
,可立刻打印输出已完成部分。
[13:45sxuan@hulab~]$parallel-j2'printf"%s-start\n%s"{}{};sleep{};printf"%s\n"-middle;echo{}-end':::4212-start2-middle2-end1-start1-middle1-end4-start4-middle4-end[13:45sxuan@hulab~]$parallel-j2--ungroup'printf"%s-start\n%s"{}{};sleep{};printf"%s\n"-middle;echo{}-end':::4214-start42-start2-middle2-end1-start1-middle1-end-middle4-end
使用 --ungroup
会很快,但会导致输出错乱,一个任务的行输出可能会被另一个任务的输出截断。像上例所示,第二行输出混合了两个任务: ‘4-middle’ ‘2-start’。使用 --linebuffer
避免这个问题(稍慢一点):
4-start2-start2-middle2-end1-start1-middle1-end4-middle4-end
强制使输出与参数保持顺序 --keep-order/-k
:
[13:53sxuan@hulab~]$parallel-j2-k'printf"%s-start\n%s"{}{};sleep{};printf"%s\n"-middle;echo{}-end':::4214-start4-middle4-end2-start2-middle2-end1-start1-middle1-end1.12 将输出保存到文件
GNU Parallel可以把每一个任务的输出保存到文件中,临时文件默认保存在 /tmp 中,可以使用 –tmpdir改变(或者修改 $TMPDIR):
[13:55sxuan@hulab~]$parallel--files:::ABC/tmp/parfmNTJ.par/tmp/parmioFz.par/tmp/pargaTxf.par[13:57sxuan@hulab~]$parallel--tmpdir~--files:::ABC/home/sxuan/parLEXH7.par/home/sxuan/parXsKsR.par/home/sxuan/parZxytI.par[13:58sxuan@hulab~]$TMPDIR=~parallel--files:::ABC/home/sxuan/par2tX6C.par/home/sxuan/parorPJy.par/home/sxuan/pari5TkI.par
输出文件可以有结构的保存 --results
,输出文件不仅包含标准输出(stdout)也会包含标准错误输出(stderr):
[13:59sxuan@hulab~]$parallel--resultsoutdirecho:::ABCABC[14:00sxuan@hulab~]$treeoutdir/outdir/└──1├──A│├──seq│├──stderr│└──stdout├──B│├──seq│├──stderr│└──stdout└──C├──seq├──stderr└──stdout4directories,9files
在使用多个变量的时候会显示很有用:
#--header:willtakethefirstvalueasnameandusethatinthedirectorystructure.[14:02sxuan@hulab~]$parallel--header:--resultsoutdirecho:::f1AB:::f2CDACADBCBD[14:02sxuan@hulab~]$treeoutdir/outdir/└──f1├──A│└──f2│├──C││├──seq││├──stderr││└──stdout│└──D│├──seq│├──stderr│└──stdout└──B└──f2├──C│├──seq│├──stderr│└──stdout└──D├──seq├──stderr└──stdout9directories,12files1.13 控制执行
使用 –jobs/-j 指定并行任务数。
#使用64个任务执行128个休眠命令[15:02sxuan@hulab~]$timeparallel-N0-j64sleep1:::{1..128}real0m2.759suser0m0.657ssys0m1.345s#默认情况下并行任务数与cpu核心数相同,所以这条命令会比每个cpu两个任务的耗时多一倍[15:03sxuan@hulab~]$timeparallel-N0sleep1:::{1..128}real0m3.478suser0m0.656ssys0m1.344s#每个cpu两个任务[15:03sxuan@hulab~]$timeparallel-N0--jobs200%sleep1:::{1..128}real0m2.659suser0m0.734ssys0m1.423s#使用--jobs0表示执行尽可能多的并行任务[15:03sxuan@hulab~]$timeparallel-N0--jobs0sleep1:::{1..128}real0m2.135suser0m0.651ssys0m1.477s#除了基于cpu使用率之外,也可以基于cpu数[15:03sxuan@hulab~]$timeparallel--use-cpus-instead-of-cores-N0sleep1:::{1..128}real1m5.499suser0m0.950ssys0m1.897s1.14 交互
通过使用 --interactive
在一个任务执行之前让用户决定是否执行。
[15:08sxuan@hulab~]$parallel--interactiveecho:::123echo1?...yecho2?...yecho3?...y1231.15 耗时
当job有大量的IO操作时,为避免“惊群效应”,可使用--delay
参数指定各个job开始的时间间隔。
[15:16sxuan@hulab~]$parallel--delay2.5echoStarting{}\;date:::123Starting1TueApr1715:21:41CST2018Starting2TueApr1715:21:44CST2018Starting3TueApr1715:21:46CST2018
若已知任务超过一定时间未反应则为失败则可以通过--timeout
指定等待时间避免无谓的等待。GNU parallel能计算所有任务运行时间的中位数,因此可以指定时间为中位数的倍数关系。
[15:35sxuan@hulab~]$parallel--timeout4.1sleep{}\;echo{}:::246824[15:36sxuan@hulab~]$parallel--timeout200%sleep{}\;echo{}:::2.12.2372.32.12.22.331.16 显示任务进度信息
GNU parallel有多种方式可用来动态的显示任务进度信息,如:
parallel--etasleep:::132213321parallel--progresssleep:::132213321seq1000|parallel-j10--bar'(echo-n{};sleep0.1)'2>>(zenity--progress--auto-kill--auto-close)
使用--joblog
参数能够生成各个任务的日志文件:
[15:39sxuan@hulab~]$parallel--joblog/tmp/logexit:::1230[15:41sxuan@hulab~]$cat/tmp/logSeqHostStarttimeJobRuntimeSendReceiveExitvalSignalCommand1:1523950890.3440.0180010exit12:1523950890.3500.0140020exit23:1523950890.3570.0060030exit34:1523950890.3630.0060000exit0
通过--resume-failed
参数可以重新运行失败的任务; --retry-failed
的作用与--resume-failed
类似,只是--resume-failed
从命令行读取失败任务,而--retry-failed
则是从日志文件中读取失败任务:
[15:41sxuan@hulab~]$parallel--resume-failed--joblog/tmp/logexit:::123000[15:48sxuan@hulab~]$cat/tmp/logSeqHostStarttimeJobRuntimeSendReceiveExitvalSignalCommand1:1523950890.3440.0180010exit12:1523950890.3500.0140020exit23:1523950890.3570.0060030exit34:1523950890.3630.0060000exit01:1523951289.5750.0290010exit12:1523951289.5800.0250020exit23:1523951289.5850.0190030exit35:1523951289.5910.0130000exit06:1523951289.6040.0040000exit0[15:48sxuan@hulab~]$parallel--retry-failed--joblog/tmp/log[15:50sxuan@hulab~]$cat/tmp/logSeqHostStarttimeJobRuntimeSendReceiveExitvalSignalCommand1:1523950890.3440.0180010exit12:1523950890.3500.0140020exit23:1523950890.3570.0060030exit34:1523950890.3630.0060000exit01:1523951289.5750.0290010exit12:1523951289.5800.0250020exit23:1523951289.5850.0190030exit35:1523951289.5910.0130000exit06:1523951289.6040.0040000exit01:1523951445.0890.0130010exit12:1523951445.0940.0090020exit23:1523951445.1020.0070030exit31.17 终止任务
GNU parallel支持在某一情况下(如第一个失败或成功时,或者20%任务失败时)终止任务,终止任务又有两种类型,其一为立即终止(通过--halt now
指定),杀死所有正在运行的任务并停止生成新的任务,其二为稍后终止(通过--halt soon
指定),停止生成新任务并等待正在运行任务完成。
[15:50sxuan@hulab~]$parallel-j2--haltsoon,fail=1echo{}\;exit{}:::00123001parallel:Thisjobfailed:echo1;exit1parallel:Startingnomorejobs.Waitingfor1jobstofinish.2parallel:Thisjobfailed:echo2;exit2[16:04sxuan@hulab~]$parallel-j2--haltnow,fail=1echo{}\;exit{}:::00123001parallel:Thisjobfailed:echo1;exit1[16:05sxuan@hulab~]$parallel-j2--haltsoon,fail=20%echo{}\;exit{}:::012345678901parallel:Thisjobfailed:echo1;exit12parallel:Thisjobfailed:echo2;exit2parallel:Startingnomorejobs.Waitingfor1jobstofinish.3parallel:Thisjobfailed:echo3;exit3[16:05sxuan@hulab~]$parallel-j2--haltnow,success=1echo{}\;exit{}:::12304561230parallel:Thisjobsucceeded:echo0;exit0
GNU parallel还支持在任务失败后重试运行--retries
:
[16:06sxuan@hulab~]$parallel-k--retries3'echotried{}>>/tmp/runs;echocompleted{};exit{}':::120completed1completed2completed0[16:09sxuan@hulab~]$cat/tmp/runstried1tried2tried0tried1tried2tried1tried2
关于终止信号的高级用法参考官方入门文档。
1.18 资源限制GNU parallel能够在开始一个新的任务前检查系统的负载情况防止过载(通过--load
可指定负载),同时还能检查系统是否使用了交换空间(swap)(通过--noswap
限制使用swap)。
[16:09sxuan@hulab~]$parallel--load100%echoloadislessthan{}jobpercpu:::1loadislessthan1jobpercpu[16:19sxuan@hulab~]$parallel--noswapechothesystemisnotswapping:::nowthesystemisnotswappingnow
同时,对于某些占用内存较多的程序,parallel会检查内存只有内存满足时才启动任务(通过--memfree
指定需要内存大小),而且在启动任务后内存不够50%时会杀掉最新开始的任务,直到这个任务完成再重新开始那些杀死的任务。
[16:24sxuan@hulab~]$parallel--memfree1Gechowillrunifmorethan1GBis:::freewillrunifmorethan1GBisfree
还可以通过--nice
来指定任务的优先级。
[16:27sxuan@hulab~]$parallel--nice17echothisisbeingrunwithnice-n:::17thisisbeingrunwithnice-n171.19 远程操作
可使用-S host
来进行远程登陆: parallel -S username@$SERVER1 echo running on ::: username@$SERVER1
GNU parallel 文件传输使用的是rsync。
echoThisisinput_file>input_fileparallel-S$SERVER1--transferfile{}cat:::input_file
更多远程操作参见入门文档。
1.21 –pipe--pipe
参数使得我们可以将输入(stdin)分为多块(block),然后分配给多个任务多个cpu以达到负载均衡,最后的结果顺序与原始顺序一致。使用--block
参数可以指定每块的大小,默认为1M。
[17:15sxuan@hulab~]$perl-e'for(1..1000000){print"$_\n"}'>num1000000[17:16sxuan@hulab~]$catnum1000000|parallel--pipewc1656681656681048571149796149796104857214979614979610485721497961497961048572149796149796104857214979614979610485728535285352597465
如果不关心结果顺序,只想要快速的得到结果,可使用--round-robin
参数。没有这个参数时每块文件都会启动一个命令,使用这个参数后会将这些文件块分配给job数任务(通过--jobs
进行指定)。若想分配更为均匀还可同时指定--block
参数。
[17:17sxuan@hulab~]$catnum1000000|parallel--pipe-j4--round-robinwc2995922995922097144315464315464209714314979614979610485722351482351481646037[17:23sxuan@hulab~]$catnum1000000|parallel--pipe-j4--block2M--round-robinwc2995932995932097151315465315465209715029959329959320971518534985349597444
“Linux并行作业执行工具GNU Parallel怎么用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。