将您的计算机变成一个多任务的动力室。

转载自:https://linux.cn/article-9718-1.html

你是否有过这种感觉,你的主机运行速度没有预期的那么快?我也曾经有过这种感觉,直到我发现了 GNU Parallel。

GNU Parallel 是一个 shell 工具,可以并行执行任务。它可以解析多种输入,让你可以同时在多份数据上运行脚本或命令。你终于可以使用全部的 CPU 了!

如果你用过 xargs,上手 Parallel 几乎没有难度。如果没有用过,这篇教程会告诉你如何使用,同时给出一些其它的用例。

安装 GNU Parallel

GNU Parallel 很可能没有预装在你的 Linux 或 BSD 主机上,你可以从软件源中安装。以 Fedora 为例:

  1. $ sudo dnf install parallel

对于 NetBSD:

  1. # pkg_add parallel

如果各种方式都不成功,请参考项目主页。

从串行到并行

正如其名称所示,Parallel 的强大之处是以并行方式执行任务;而我们中不少人平时仍然以串行方式运行任务。

当你对多个对象执行某个命令时,你实际上创建了一个任务队列。一部分对象可以被命令处理,剩余的对象需要等待,直到命令处理它们。这种方式是低效的。只要数据够多,总会形成任务队列;但与其只使用一个任务队列,为何不使用多个更小规模的任务队列呢?

假设你有一个图片目录,你希望将目录中的图片从 JEEG 格式转换为 PNG 格式。有多种方法可以完成这个任务。可以手动用 GIMP 打开每个图片,输出成新格式,但这基本是最差的选择,费时费力。

上述方法有一个漂亮且简洁的变种,即基于 shell 的方案:

  1. $ convert 001.jpeg 001.png
  2. $ convert 002.jpeg 002.png
  3. $ convert 003.jpeg 003.png
  4. ... 略 ...

对于初学者而言,这是一个不小的转变,而且看起来是个不小的改进。不再需要图像界面和不断的鼠标点击,但仍然是费力的。

进一步改进:

  1. $ for i in *jpeg; do convert $i $i.png ; done

至少,这一步设置好任务执行,让你节省时间去做更有价值的事情。但问题来了,这仍然是串行操作;一张图片转换完成后,队列中的下一张进行转换,依此类推直到全部完成。

使用 Parallel:

  1. $ find . -name "*jpeg" | parallel -I% --max-args 1 convert % %.png

这是两条命令的组合:find 命令,用于收集需要操作的对象;parallel 命令,用于对象排序并确保每个对象按需处理。

  • find . -name "*jpeg" 查找当前目录下以 jpeg 结尾的所有文件。
  • parallel 调用 GNU Parallel。
  • -I% 创建了一个占位符 %,代表 find 传递给 Parallel 的内容。如果不使用占位符,你需要对 find 命令的每一个结果手动编写一个命令,而这恰恰是你想要避免的。
  • --max-args 1 给出 Parallel 从队列获取新对象的速率限制。考虑到 Parallel 运行的命令只需要一个文件输入,这里将速率限制设置为 1。假如你需要执行更复杂的命令,需要两个文件输入(例如 cat 001.txt 002.txt > new.txt),你需要将速率限制设置为 2。
  • convert % %.png 是你希望 Parallel 执行的命令。

组合命令的执行效果如下:find 命令收集所有相关的文件信息并传递给 parallel,后者(使用当前参数)启动一个任务,(无需等待任务完成)立即获取参数行中的下一个参数(LCTT 译注:管道输出的每一行对应 parallel 的一个参数,所有参数构成参数行);只要你的主机没有瘫痪,Parallel 会不断做这样的操作。旧任务完成后,Parallel 会为分配新任务,直到所有数据都处理完成。不使用 Parallel 完成任务大约需要 10 分钟,使用后仅需 3 至 5 分钟。

多个输入

只要你熟悉 find 和 xargs (整体被称为 GNU 查找工具,或 findutils),find 命令是一个完美的 Parallel 数据提供者。它提供了灵活的接口,大多数 Linux 用户已经很习惯使用,即使对于初学者也很容易学习。

find 命令十分直截了当:你向 find 提供搜索路径和待查找文件的一部分信息。可以使用通配符完成模糊搜索;在下面的例子中,星号匹配任何字符,故 find定位(文件名)以字符 searchterm 结尾的全部文件:

  1. $ find /path/to/directory -name "*searchterm"

默认情况下,find 逐行返回搜索结果,每个结果对应 1 行:

  1. $ find ~/graphics -name "*jpg"
  2. /home/seth/graphics/001.jpg
  3. /home/seth/graphics/cat.jpg
  4. /home/seth/graphics/penguin.jpg
  5. /home/seth/graphics/IMG_0135.jpg

当使用管道将 find 的结果传递给 parallel 时,每一行中的文件路径被视为 parallel 命令的一个参数。另一方面,如果你需要使用命令处理多个参数,你可以改变队列数据传递给 parallel 的方式。

下面先给出一个不那么实际的例子,后续会做一些修改使其更加有意义。如果你安装了 GNU Parallel,你可以跟着这个例子操作。

假设你有 4 个文件,按照每行一个文件的方式列出,具体如下:

  1. $ echo ada > ada ; echo lovelace > lovelace
  2. $ echo richard > richard ; echo stallman > stallman
  3. $ ls -1
  4. ada
  5. lovelace
  6. richard
  7. stallman

你需要将两个文件合并成第三个文件,后者同时包含前两个文件的内容。这种情况下,Parallel 需要访问两个文件,使用 -I% 变量的方式不符合本例的预期。

Parallel 默认情况下读取 1 个队列对象:

  1. $ ls -1 | parallel echo
  2. ada
  3. lovelace
  4. richard
  5. stallman

现在让 Parallel 每个任务使用 2 个队列对象:

  1. $ ls -1 | parallel --max-args=2 echo
  2. ada lovelace
  3. richard stallman

现在,我们看到行已经并合并;具体而言,ls -1 的两个查询结果会被同时传送给 Parallel。传送给 Parallel 的参数涉及了任务所需的 2 个文件,但目前还只是 1 个有效参数:(对于两个任务分别为)“ada lovelace” 和 “richard stallman”。你真正需要的是每个任务对应 2 个独立的参数。

值得庆幸的是,Parallel 本身提供了上述所需的解析功能。如果你将 --max-args 设置为 2,那么 {1} 和 {2} 这两个变量分别代表传入参数的第一和第二部分:

  1. $ 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

  1. $ ls -1
  2. ada
  3. ada_lovelace.person
  4. lovelace
  5. richard
  6. richard_stallman.person
  7. stallman
  8. $ cat ada_*person
  9. ada lovelace
  10. $ cat ri*person
  11. richard stallman

如果你整天处理大量几百 MB 大小的日志文件,那么(上述)并行处理文本的方法对你帮忙很大;否则,上述例子只是个用于上手的示例。

然而,这种处理方法对于很多文本处理之外的操作也有很大帮助。下面是来自电影产业的真实案例,其中需要将一个目录中的视频文件和(对应的)音频文件进行合并。

  1. $ ls -1
  2. 12_LS_establishing-manor.avi
  3. 12_wildsound.flac
  4. 14_butler-dialogue-mixed.flac
  5. 14_MS_butler.avi
  6. ...略...

使用同样的方法,使用下面这个简单命令即可并行地合并文件:

  1. $ ls -1 | parallel --max-args=2 ffmpeg -i {1} -i {2} -vcodec copy -acodec copy {1}.mkv

简单粗暴的方式

上述花哨的输入输出处理不一定对所有人的口味。如果你希望更直接一些,可以将一堆命令甩给 Parallel,然后去干些其它事情。

首先,需要创建一个文本文件,每行包含一个命令:

  1. $ cat jobs2run
  2. bzip2 oldstuff.tar
  3. oggenc music.flac
  4. opusenc ambiance.wav
  5. convert bigfile.tiff small.jpeg
  6. ffmepg -i foo.avi -v:b 12000k foo.mp4
  7. xsltproc --output build/tmp.fo style/dm.xsl src/tmp.xml
  8. bzip2 archive.tar

接着,将文件传递给 Parallel:

  1. $ parallel --jobs 6 < jobs2run

现在文件中对应的全部任务都在被 Parallel 执行。如果任务数量超过允许的数目(LCTT 译注:应该是 --jobs 指定的数目或默认值),Parallel 会创建并维护一个队列,直到任务全部完成。

更多内容

GNU Parallel 是个强大而灵活的工具,还有很多很多用例无法在本文中讲述。工具的 man 页面提供很多非常酷的例子可供你参考,包括通过 SSH 远程执行和在 Parallel 命令中使用 Bash 函数等。YouTube 上甚至有一个系列,包含大量操作演示,让你可以直接从 GNU Parallel 团队学习。GNU Paralle 的主要维护者还发布了官方使用指导手册,可以从 Lulu.com 获取。

GNU Parallel 有可能改变你完成计算的方式;即使没有,也会至少改变你主机花在计算上的时间。马上上手试试吧!

使用 GNU Parallel 提高 Linux 命令行执行效率相关推荐

  1. 使用 Parallel 提高 Linux 命令行执行效率

    你是否有过这种感觉,你的主机运行速度没有预期的那么快?我也曾经有过这种感觉,直到我发现了 GNU Parallel. GNU Parallel 是一个 shell 工具,可以并行执行任务.它可以解析多 ...

  2. gnu parallel_使用GNU Parallel在Linux命令行上完成更多工作

    gnu parallel 您是否曾经获得过一种有趣的感觉,那就是您的计算机并没有达到应有的速度? 我曾经有这种感觉,然后我找到了GNU Parallel. GNU Parallel是用于并行执行作业的 ...

  3. Linux命令行执行sqlite3命令创建表格,插入数据,获取数据

    Linux命令行执行sqlite3命令创建表格,插入数据,获取数据 文章目录 Linux命令行执行sqlite3命令创建表格,插入数据,获取数据 1-进入sqlite3 2-创建数据库 3-创建表 4 ...

  4. linux命令行执行mysql语句_linux命令行中直接执行mysql语句

    其实我一开始是拒绝的,但是貌似就得这么做.怎么一行一行的来?没法整了. 有两种方法可以在命令行下执行sql命令.第一种是使用"-e"参数来指定需要执行的sql语句:第二种是通过管道 ...

  5. 在linux命令行下载百度网盘中的文件

    在linux命令行下载百度网盘中的文件 将想下载的文件创建一个公开链接, 然后在浏览器里输入链接地址,单击下载,之后浏览器会下载文件,此时取消下载,然后右键复制下载链接地址. linux命令行执行如下 ...

  6. Linux命令行——光标快速移动的快捷键

    linux命令行执行命令时,快速移动光标可节省不少时间,如下是快速移动光标的快捷键: 1.光标快速切换到行尾行首 ctrl+a 行首 ctrl+e 行尾 2.删除至行尾 | 清除当前光标位置之前的一个 ...

  7. 使用Linux命令行技术提高工作效率

    这篇文章是当时参加网络系统空间竞赛时老师给的总结性的文章让我们好好看,当时不以为然,觉得没啥好看的,都是些基础的命令. 但是过了两年时间,期间也用了好长时间的Linux系统,在回头看这篇文章时还是能够 ...

  8. java 执行linux命令行_10个高效Linux技巧及Vim命令对比

    专注于Java领域优质技术,欢迎关注 作者:vimtutor 来自:Vim教程网 Vim的很多命令和功能与Linux系统的命令和功能及其相似,可以说是一脉相承.Vim教程网(https://vimjc ...

  9. linux php 指令,在 Linux 命令行中使用和执行 PHP 代码(一)

    PHP是一个开源服务器端脚本语言,最初这三个字母代表的是"Personal Home Page",而现在则代表的是"PHP:Hypertext Preprocessor& ...

最新文章

  1. TikTok太火,Netflix急了
  2. SkyWalking之高级玩法
  3. Logistic回归模型原理
  4. Struts2学习笔记(六) 结果(Result)(上)
  5. multisim变压器反馈式_【鼎阳硬件智库原创|高速总线】 以太网变压器反转问题技术分析...
  6. hdu 1712 ACboy needs your help (DP)
  7. Java语言学习指导与习题解答_Java语言程序设计(第3版)学习指导与习题解析
  8. 简单介绍谷歌关键词扩展工具
  9. “好工作”的最关键指标:场景足够复杂、数据量足够大、杠杆率足够高
  10. 扁平化设计的色彩选择
  11. 案例分享 | 腾讯互娱基于 CPU 环境的分布式 YOLOv3 实现
  12. 单片机芯片解密OTP存储器加密
  13. java hypot_java.lang.StrictMath.hypot()方法实例
  14. 全球电动汽车充电标准最详解析
  15. WLAN——一篇让你从0到1了解无线局域网的文章
  16. 影驰gtx960显卡怎么样_影驰gtx960 2g_影驰gtx960 2g跑分
  17. 瘦客户机为何不瘦反胖?
  18. win7忘记密码怎么办,Administrator忘记密码解决办法【完美、简单、有效】
  19. 1095 Anigram单词
  20. 【微机原理 实验】可编程外围接口芯片8255(4)(硬件-含汇编代码)

热门文章

  1. 动态规划报告(树形DP+概率DP
  2. Android Framework学习(八)之Handler消息机制(Native层)解析
  3. 理财入门类书籍读书笔记
  4. 如何实现QSV转mp4呢?
  5. android服务绑定音乐播放器,Android基于Service的音乐播放器
  6. 电脑装Windows+Ubuntu双系统,及后续调整硬盘和系统重装之后相关的引导问题
  7. 技术如何革新工作场所的生产力
  8. Android仿ios年龄滚轮大全
  9. 一点经验分享:软件安装常见问题及管理...(文末附带重装系统)
  10. shopnc二次开发(一)