你是否有过这种感受,你的主机运行速度没有预期的那么快?我也曾经有过这种感受,直到我发现了 GNU Parallel。html
GNU Parallel 是一个 shell 工具,能够并行执行任务。它能够解析多种输入,让你能够同时在多份数据上运行脚本或命令。你终于可使用所有的 CPU 了!linux
若是你用过 xargs,上手 Parallel 几乎没有难度。若是没有用过,这篇教程会告诉你如何使用,同时给出一些其它的用例。git
安装 GNU Parallelgithub
GNU Parallel 极可能没有预装在你的 Linux 或 BSD 主机上,你能够从软件源中安装。以 Fedora 为例:shell
$ sudo dnf install parallel
对于 NetBSD:函数
# pkg_add parallel
若是各类方式都不成功,请参考项目主页[1]。工具
从串行到并行学习
正如其名称所示,Parallel 的强大之处是以并行方式执行任务;而咱们中很多人平时仍然以串行方式运行任务。ui
当你对多个对象执行某个命令时,你实际上建立了一个任务队列。一部分对象能够被命令处理,剩余的对象须要等待,直到命令处理它们。这种方式是低效的。只要数据够多,总会造成任务队列;但与其只使用一个任务队列,为什么不使用多个更小规模的任务队列呢?命令行
假设你有一个图片目录,你但愿将目录中的图片从 JEEG 格式转换为 PNG 格式。有多种方法能够完成这个任务。能够手动用 GIMP 打开每一个图片,输出成新格式,但这基本是最差的选择,费时费力。
上述方法有一个漂亮且简洁的变种,即基于 shell 的方案:
$ convert 001.jpeg 001.png $ convert 002.jpeg 002.png $ convert 003.jpeg 003.png ... 略 ...
对于初学者而言,这是一个不小的转变,并且看起来是个不小的改进。再也不须要图像界面和不断的鼠标点击,但仍然是费力的。
进一步改进:
$ for i in *jpeg; do convert $i $i.png ; done
至少,这一步设置好任务执行,让你节省时间去作更有价值的事情。但问题来了,这仍然是串行操做;一张图片转换完成后,队列中的下一张进行转换,依此类推直到所有完成。
使用 Parallel:
$ find . -name "*jpeg" | parallel -I% --max-args 1 convert % %.png
这是两条命令的组合:find 命令,用于收集须要操做的对象;parallel 命令,用于对象排序并确保每一个对象按需处理。
组合命令的执行效果以下:find 命令收集全部相关的文件信息并传递给 parallel,后者(使用当前参数)启动一个任务,(无需等待任务完成)当即获取参数行中的下一个参数(LCTT 译注:管道输出的每一行对应 parallel 的一个参数,全部参数构成参数行);只要你的主机没有瘫痪,Parallel 会不断作这样的操做。旧任务完成后,Parallel 会为分配新任务,直到全部数据都处理完成。不使用 Parallel 完成任务大约须要 10 分钟,使用后仅需 3 至 5 分钟。
多个输入
只要你熟悉 find 和 xargs (总体被称为 GNU 查找工具,或 findutils),find 命令是一个完美的 Parallel 数据提供者。它提供了灵活的接口,大多数 Linux 用户已经很习惯使用,即便对于初学者也很容易学习。
find 命令十分直截了当:你向 find 提供搜索路径和待查找文件的一部分信息。可使用通配符完成模糊搜索;在下面的例子中,星号匹配任何字符,故 find 定位(文件名)以字符 searchterm 结尾的所有文件:
$ find /path/to/directory -name "*searchterm"
默认状况下,find 逐行返回搜索结果,每一个结果对应 1 行:
$ find ~/graphics -name "*jpg" /home/seth/graphics/001.jpg /home/seth/graphics/cat.jpg /home/seth/graphics/penguin.jpg /home/seth/graphics/IMG_0135.jpg
当使用管道将 find 的结果传递给 parallel 时,每一行中的文件路径被视为 parallel 命令的一个参数。另外一方面,若是你须要使用命令处理多个参数,你能够改变队列数据传递给 parallel 的方式。
下面先给出一个不那么实际的例子,后续会作一些修改使其更加有意义。若是你安装了 GNU Parallel,你能够跟着这个例子操做。
假设你有 4 个文件,按照每行一个文件的方式列出,具体以下:
$ echo ada > ada ; echo lovelace > lovelace $ echo richard > richard ; echo stallman > stallman $ ls -1 ada lovelace richard stallman
你须要将两个文件合并成第三个文件,后者同时包含前两个文件的内容。这种状况下,Parallel 须要访问两个文件,使用 -I% 变量的方式不符合本例的预期。
Parallel 默认状况下读取 1 个队列对象:
$ ls -1 | parallel echo ada lovelace richard stallman
如今让 Parallel 每一个任务使用 2 个队列对象:
$ ls -1 | parallel --max-args=2 echo ada lovelace richard stallman
如今,咱们看到行已经并合并;具体而言,ls -1 的两个查询结果会被同时传送给 Parallel。传送给 Parallel 的参数涉及了任务所需的 2 个文件,但目前还只是 1 个有效参数:(对于两个任务分别为)“ada lovelace” 和 “richard stallman”。你真正须要的是每一个任务对应 2 个独立的参数。
值得庆幸的是,Parallel 自己提供了上述所需的解析功能。若是你将 --max-args 设置为 2,那么 {1}和 {2} 这两个变量分别表明传入参数的第一和第二部分:
$ ls -1 | parallel --max-args=2 cat {1} {2} ">" {1}_{2}.person
在上面的命令中,变量 {1} 值为 ada 或 richard (取决于你选取的任务),变量 {2} 值为 lovelace 或 stallman。经过使用重定向符号(放到引号中,防止被 Bash 识别,以便 Parallel 使用),(两个)文件的内容被分别重定向至新文件 ada_lovelace.person 和 richard_stallman.person。
$ ls -1 ada ada_lovelace.person lovelace richard richard_stallman.person stallman $ cat ada_*person ada lovelace $ cat ri*person richard stallman
若是你成天处理大量几百 MB 大小的日志文件,那么(上述)并行处理文本的方法对你帮忙很大;不然,上述例子只是个用于上手的示例。
然而,这种处理方法对于不少文本处理以外的操做也有很大帮助。下面是来自电影产业的真实案例,其中须要将一个目录中的视频文件和(对应的)音频文件进行合并。
$ ls -1 12_LS_establishing-manor.avi 12_wildsound.flac 14_butler-dialogue-mixed.flac 14_MS_butler.avi ...略...
使用一样的方法,使用下面这个简单命令便可并行地合并文件:
$ ls -1 | parallel --max-args=2 ffmpeg -i {1} -i {2} -vcodec copy -acodec copy {1}.mkv
简单粗暴的方式
上述花哨的输入输出处理不必定对全部人的口味。若是你但愿更直接一些,能够将一堆命令甩给 Parallel,而后去干些其它事情。
首先,须要建立一个文本文件,每行包含一个命令:
$ cat jobs2run bzip2 oldstuff.tar oggenc music.flac opusenc ambiance.wav convert bigfile.tiff small.jpeg ffmepg -i foo.avi -v:b 12000k foo.mp4 xsltproc --output build/tmp.fo style/dm.xsl src/tmp.xml bzip2 archive.tar
接着,将文件传递给 Parallel:
$ parallel --jobs 6 < jobs2run
如今文件中对应的所有任务都在被 Parallel 执行。若是任务数量超过容许的数目(LCTT 译注:应该是 --jobs 指定的数目或默认值),Parallel 会建立并维护一个队列,直到任务所有完成。
更多内容
GNU Parallel 是个强大而灵活的工具,还有不少不少用例没法在本文中讲述。工具的 man 页面提供不少很是酷的例子可供你参考,包括经过 SSH 远程执行和在 Parallel 命令中使用 Bash 函数等。YouTube[2] 上甚至有一个系列,包含大量操做演示,让你能够直接从 GNU Parallel 团队学习。GNU Paralle 的主要维护者还发布了官方使用指导手册,能够从 Lulu.com[3] 获取。
GNU Parallel 有可能改变你完成计算的方式;即便没有,也会至少改变你主机花在计算上的时间。立刻上手试试吧!
via: https://opensource.com/article/18/5/gnu-parallel
做者:Seth Kenlon[4] 选题:lujun9972[5] 译者:pinewall[6] 校对:wxy[7]
本文由 LCTT[8] 原创编译,Linux中国[9] 荣誉推出