当前位置: 首页 > 科技观察

如何使用GNUParallel提高Linux命令行执行效率

时间:2023-03-17 00:34:50 科技观察

将您的计算机变成多任务处理的动力源。您是否曾感觉您的主机运行速度没有达到应有的速度?在我发现GNUParallel之前,我也曾有过这种感觉。GNUParallel是一个并行执行任务的shell实用程序。它可以解析各种输入,允许您同时在多个数据副本上运行脚本或命令。您终于可以使用完整的CPU了!如果你用过xargs,Parallel上手几乎没有难度。如果你还没有使用过它,本教程将告诉你如何使用它,并给出一些其他的用例。安装GNUParallelGNUParallel可能没有预装在您的Linux或BSD主机上,您可以从软件源安装它。以Fedora为例:$sudodnfinstallparallel对于NetBSD:#pkg_addparallel如果所有方法都失败,请参考项目主页。FromSerialtoParallel顾名思义,Parallel的威力在于并行执行任务;我们中的许多人仍然连续运行任务。当你在多个对象上执行一个命令时,你实际上创建了一个任务队列。一些对象可以被命令处理,剩下的对象需要等到命令处理它们。这种方法效率低下。只要有足够的数据,总会有一个任务队列;但与其只使用一个任务队列,不如使用多个更小的任务队列?假设你有一个图像目录,你想将目录中的图像从JEEG格式转换为PNG格式。有多种方法可以完成此任务。可以在GIMP中手动打开每个图像并将其导出为新格式,但这基本上是最糟糕的选择,耗时耗力。上面有一个很好的变体,基于shell的方案:$convert001.jpeg001.png$convert002.jpeg002.png$convert003.jpeg003.png...稍微...对于初学者这不是一个小转变,而且看起来是一个很大的进步。不再需要图形界面和不断的鼠标点击,但仍然很费力。进一步改进:$foriin*jpeg;转换$i$i.png;done至少,这一步设置了任务执行,让你节省时间去做更有价值的事情。但是问题来了,这仍然是一个串行操作;转换完一张图像后,将转换队列中的下一张图像,依此类推,直到全部完成。使用并行:$find。-名称“*jpeg”|parallel-I%--max-args1convert%%.png这是两个命令的组合:find命令用于收集需要操作的对象;并行命令,用于对象排序并确保按需处理每个对象。寻找。-name"*jpeg"查找当前目录中所有以jpeg结尾的文件。parallel调用GNUParallel。-I%为find传递给Parallel的内容创建一个占位符%。如果没有占位符,您需要为find命令的每个结果手动编写命令,这正是您想要避免的。--max-args1为Parallel提供从队列中获取新对象的速率限制。考虑到Parallel运行的命令只需要单个文件输入,这里将速率限制设置为1。如果您需要执行需要两个文件输入的更复杂的命令(例如cat001.txt002.txt>new.txt),您需要将速率限制设置为2。convert%%.png是您想要并行的命令执行。组合命令的工作方式如下:find命令收集所有相关文件信息并将其传递给parallel,它(使用当前参数)启动任务并且(无需等待任务完成)立即获取参数行中的下一个参数(LCTTAnnotation:pipeline输出的每一行对应parallel的一个参数,所有参数构成一个parameterline);只要你的主机没有瘫痪,Parallel就会继续做这个操作。旧任务完成后,Parallel会为其分配新任务,直到处理完所有数据。不使用Parallel完成任务大约需要10分钟,使用它只需3到5分钟。多输入只要您熟悉find和xargs(统称为GNU查找工具或findutils),find命令就是一个出色的并行数据提供程序。它提供了大多数Linux用户已经熟悉的灵活界面,即使对于初学者也很容易学习。find命令非常简单:您为find提供搜索路径和有关要查找的文件的一些信息。可以使用通配符进行模糊搜索;在下面的示例中,星号匹配任何字符,因此find定位所有以字符searchterm结尾的文件:$find/path/to/directory-name"*searchterm"bydefault接下来,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命令的参数。另一方面,如果你需要用一个命令处理多个参数,你可以改变队列数据传递的方式为并行。下面是一个不太实际的例子,后面会做一些修改,让它更有意义。如果您安装了GNUParallel,则可以按照此示例进行操作。假设你有4个文件,每行列出一个文件,如下所示:$echoada>ada;echolovelace>lovelace$echorichard>richard;echostallman>stallman$ls-1adalovelacerichardstallman您需要合并这两个文件合并到包含前两个文件内容的第三个文件中。在这种情况下,Parallel需要访问两个文件,并且使用-I%变量不会像本示例中预期的那样工作。默认并行读取1个队列对象:$ls-1|parallelechoadalovelacerichardstallman现在告诉Parallel每个任务使用2个队列对象:$ls-1|parallel--max-args=2echoadalovelacerichardstallman现在,我们看到行已经合并;具体来说,ls-1的两个查询结果同时发送给Parallel。传递给Parallel的参数是指任务需要的2个文件,但目前只有1个有效参数:(分别针对两个任务)“adalovelace”和“richardstallman”。您真正需要的是为每个任务设置2个单独的参数。值得庆幸的是,Parallel本身提供了上述所需的解析功能。如果将--max-args设置为2,则变量{1}和{2}分别表示传入参数的第一部分和第二部分:$ls-1|parallel--max-args=2cat{1}{2}">"{1}_{2}.person在上面的命令中,变量{1}的值是ada或richard(取决于你选择的任务),变量{2}的值为lovelace或stallman。通过使用重定向符号(用引号引起来以防止被Bash识别,以便Parallel可以使用它),(两个)文件的内容分别重定向到新文件ada_lovelace.person和richard_stallman.person。$ls-1adaada_lovelace.personlovelacerichardrichard_stallman.personstallman$catada_*personadalovelace$catri*personrichardstallman如果整天处理大量几百MB大小的日志文件,(上面的)并行化文本处理的方法将是对你有很大帮助;否则,上面的示例只是一个入门示例。不过,这种处理方式对于文本处理以外的很多操作也很有帮助。这是电影行业的真实示例,其中需要合并目录中的视频文件和(相应的)音频文件。$ls-112_LS_establishing-manor.avi12_wildsound.flac14_butler-dialogue-mixed.flac14_MS_butler.avi...同理,使用以下简单命令并行合并文件:$ls-1|parallel--max-args=2ffmpeg-i{1}-i{2}-vcodeccopy-acodeccopy{1}.mkv简单粗暴的方式上面花哨的输入输出处理可能不是每个人的口味。如果你想更直接,你可以将一堆命令转储到Parallel并去做其他事情。首先,您需要创建一个文本文件,每行一个命令:$catjobs2runbzip2oldstuff.taroggencmusic.flacopusencambiance.wavconvertbigfile.tiffsmall.jpegffmepg-ifoo.avi-v:b12000kfoo.mp4xsltproc--outputbuild/tmp.fostyle/dm.xslsrc/tmp.xmlbzip2archive.tar接下来,将文件传递给Parallel:$parallel--jobs6