我有一个脚本dataProcessing.pl
,它接受制表符分隔的.txt
文件并对所包含的数据执行大量处理任务。存在多个输入文件 ( file1.txt file2.txt file3.txt
),它们当前作为 bash 脚本的一部分循环,在每次迭代期间调用 perl(即一次处理一个输入文件)。
然而,我希望运行 Perl 的多个实例(如果可能),并通过 xargs 同时处理所有输入文件。我知道你可以运行类似的东西:
perl -e 'print "Test" x 100' | xargs -P 100
不过,我想为每个打开的 Perl 并行实例传递一个不同的文件(一个实例适用于 file1.txt,一个实例适用于 file2.txt,依此类推)。文件句柄或文件路径可以作为参数传递给 Perl。我怎样才能做到这一点?例如,我不确定如何将文件名传递给 xargs。
答案1
使用xargs
的-n 1
含义是“仅向实用程序的每次调用传递一个参数”。
就像是:
printf '%s\n' file*.txt | xargs -n 1 -P 100 perl dataProcessing.pl
它假设文件名不包含文字换行符。
如果您有 GNU或它xargs
的实现(用于读取空分隔参数,允许使用换行符的文件名)和(用于不使用空参数列表运行实用程序,当不匹配任何内容且有效时),你可以这样做xargs
-0
-r
file*.txt
nullglob
printf '%s\0' file*.txt | xargs -r0 -n 1 -P 100 perl dataProcessing.pl
请注意,这两种变体都可能启动最多 100 个脚本的并行实例,这可能不是您想要的。您可能希望将其限制为与计算机上的 CPU 数量相关的合理数字(或者与可用 RAM 总量除以每个任务的预期内存使用量(如果受内存限制)相关)。
答案2
无需在这里花哨。在 bash for 循环中,只需将 perl 进程设置为后台即可:
for f in file*.txt; do
perl dataProcessing.pl "$f" &
done
# wait for them to complete
wait
echo "All done."
答案3
GNU Parallel 正是为此而设计的:
parallel some_command {} ::: *.txt
默认情况下,每个 CPU 核心执行一项作业。如果你想并行运行 100 个作业:
parallel -j100 some_command {} ::: *.txt
了解 Perl 后,即使使用 GNU Parallel 的更高级功能,您也会感到宾至如归。你认为这有什么作用:
parallel echo '{= s/(\d+)/$1*2/e; s/(.)/uc($1)/e; s/bar/baz/; s/foo/bar/ =}' \
::: 'my foo' 'i went to a baraar to get a 12" crowfoo'
GNU Parallel 是一个通用并行器,可以轻松地在同一台计算机或多台您可以通过 ssh 访问的计算机上并行运行作业。
如果您想要在 4 个 CPU 上运行 32 个不同的作业,则并行化的直接方法是在每个 CPU 上运行 8 个作业:
相反,GNU Parallel 在完成后会生成一个新进程 - 保持 CPU 处于活动状态,从而节省时间:
安装
出于安全原因,您应该使用软件包管理器安装 GNU Parallel,但如果 GNU Parallel 未针对您的发行版打包,您可以进行个人安装,这不需要 root 访问权限。这样做可以在 10 秒内完成:
(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash
对于其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README
了解更多
查看更多示例:http://www.gnu.org/software/parallel/man.html
观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
浏览本教程:http://www.gnu.org/software/parallel/parallel_tutorial.html
注册电子邮件列表以获得支持:https://lists.gnu.org/mailman/listinfo/parallel