在bash或脚本中,如何并行执行命令或任务(命令行、parallel、make)

最近要批量解压归档文件和压缩包,所以就想能不能并行执行这些工作。因为tar自身不支持并行解压,但是像make却可以支持生成一些文件,所以我才有了这种想法。

方法有两种,第一种不用安装任何软件或工具,直接bash或其他 Shell 中就可以使用;第二种需要安装 GNU parallel 这个工具来进行。二者在使用上都很简单,但是后者更人性化(应该可以用这个词来形容)一些。最后还介绍了一种比较奇特的方法,是无意中看到的,虽然没啥用但是有点意思。

直接在命令最后使用&

这个方法需要在命令最后使用&,也就是将这个命令放入后台执行。如下是并行解压提取当前文件夹下所有的归档文件的方法:

for tarfile in *.tar; do tar xvf $tarfile &
done;

可以看到这个方法可以说是非常简单了,但是最大的问题就是它会给每个归档文件创建一个进程,并不会自动根据设备的线程数而创建合适数量的进程(tar由于需要大量 I/O,所以也无法维持高 CPU 使用率),如下:

请添加图片描述

如果是小数量的解压提取可能没什么问题,但是如果特别大数量的归档文件解压提取,那么可能会造成调度损耗过大。如果需要根据实际线程数量生成,那么就复杂多了。

使用GNU parallel

这个工具很好用,不光可以设置最大并行任务数量,还可以通过--bar选项显示当前总进度如何。使用方法如下(还是解压提取一堆归档文件):

parallel tar xvf ::: *.tar

这种方法但是像time,将需要并行化的命令放到parallel后面即可,而不同命令之间不同的地方(参数部分)使用:::标注出来。

而且相比上一种方法,默认情况下最多只会创建 CPU 的线程数的进程,而不是一次性全部生成。如下:

请添加图片描述

可以看到一开始只生成了线程数量的进程,也就是8个进程。如果想手动设定最大并行进程数量,那么使用-j 数量即可(make-j选项一样,有没有空格都行)。

管道传递参数

上面是直接可以获取参数的情况,并不存在不同程序之间通过管道(pipe)传递信息的情况。那么面对这种情况该怎么办呢?

使用{}在下一个程序的参数部分,作为即将传递的参数字符串的占位符,而且parallel也要使用在下一个程序前面。需要注意的是:传递的参数是分散开传递的。比如说一个多行字符串"1234\n1234\n1234"会被传递成三个单行字符串"1234","1234","1234"

假设一个文本文件中,每一行都是一个地址,我们想并行下载所有链接的文件,那么可以使用:

cat abc.txt | parallel wget {}

但是面对比如说使用grep批量查询abc.txt中含有abc的行有哪些,如果还使用上面这样的传递,由于是分散开传递的,那么这个单独的字符串会被当作文件名:

cat abc.txt | parallel grep abc {}

结果如下:

$ cat abc.txt | parallel grep abc {}
grep: bfjksa: No such file or directory
grep: afhjha,fsj: No such file or directory
grep: abcshjagf: No such file or directory
grep: a;hfahabc: No such file or directory
grep: ahsfhmabc: No such file or directory

在这种就不要使用并行化,因为读取硬盘上的文件实际上是串行的,对单个或多个文件使用并行读取或写入几乎不会有任何性能提升,有时甚至还会降低(跳来跳去比顺序读取当然慢了)。

比如说官方有个例子是查找当前目录下所有文件中含有某一字符串的行,这里我查找main这个字符串:

$ time find . -type f | parallel grep -H -n main {}
./mem_disk_speedtest_in_C/.git/config:10:[branch "main"]
...real    0m26.651s
user    0m3.351s
sys     0m1.030s

而不使用 GNU Parallel 的命令为(并不是直接删除parallel部分就行了,需要做出一些调整):

$ time grep -H -n main $(find . -type f)
./mem_disk_speedtest_in_C/.git/config:10:[branch "main"]
...real    0m22.247s
user    0m3.204s
sys     0m0.809s

可以看到慢了 18%。这是比较坏的情况,一般情况下,用不用 GNU Parallel 速度都没什么变化。

更多选项请见官方文档:GNU Parallel Tutorial

二者的速度区别

实际测试上,直接在命令最后使用&要比使用GNU parallel慢一些(应该就是因为调度损耗了一部份性能),如下:

方法运行时间(秒)
串行237.9
&152.1
GNU parallel121.3

但是由于这里使用的 CPU 缓存较少,所以解压速度也没有 8 倍的提升,但是提升一倍也是不错的了。

扩展

正如开头所说,make是可以并行生成一些文件,而且可以通过-j选项设置最大并行任务数量。我们也可以利用这点来解压提取文件,但这并不是一个正经的办法,仅限于开拓眼界,因为有点“脱裤子放屁”的感觉(因为生成Makefile中的target部分需要使用CMake或者Bash来自动生成),正经使用的时候还是不要使用这种方法。

这个方法是我在 Running commands in parallel with a limit of simultaneous number of commands - superuser 中看到的,进行了一些尝试,可以说除了奇特毫无优点(通用性比不过&,易用性比不过 GNU Parallel),所以不推荐使用。

参考资料

Parallelize a Bash FOR Loop - Unix StackExchange

Can I use pipe output as a shell script argument? - superuser stackexchange

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/453778.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【PCL】(十)使用StatisticalOutlierRemove滤波器除去异常点

&#xff08;十&#xff09;使用StatisticalOutlierRemove滤波器删除异常点 以下代码实现使用StatisticalOutlierRemove去去除点云的异常点。 statistical_removal.cpp #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #inc…

最值得推荐收藏的 7 款 Android 系统修复软件,快速的修复手机异常

在当今世界&#xff0c;移动设备是我们生活的重要组成部分。我们将它们用于沟通、工作、娱乐和许多其他目的。然而&#xff0c;随着不断的使用&#xff0c;它们通常会面临速度慢、崩溃等问题。这可能会让人烦恼和沮丧。但是&#xff0c;值得庆幸的是&#xff0c;您可以在 Andro…

SDL库的下载与配置(Visual Studio )2024/2/4更新

一.SDL的下载 下载链接 二.SDL的环境配置 解压以后放在中文路径下 不会添加环境变量自行搜索&#xff08;比较简单网上教程很多&#xff09; 下面进行编译器的配置 复制这段内容 x64\SDL2main.lib x64\SDL2.lib将这段代码放进去运行一下 #include <SDL.h>int main(int…

SpringMVC-组件解析

一、引子 我们在上一篇文章Spring MVC-基本概念中&#xff0c;为读者解释了如何使用SpringMVC框架&#xff0c;将承接客户端请求的工作从原生的Servlet转移到我们熟知的Controller中。那么我们不禁会好奇&#xff0c;SpringMVC框架到底做了什么&#xff0c;是怎么把请求分发给…

【Java报错】显示错误“Error:java: 程序包org.springframework.boot不存在“

使用idea运行项目&#xff0c;显示错误信息如下&#xff1a; 原因是&#xff1a;idea配置的maven加载不到autoconfigure。 解决方案一&#xff1a; 第6步绕过证书语句如下&#xff1a; -Dmaven.wagon.http.ssl.insecuretrue -Dmaven.wagon.http.ssl.allowalltrue 打开终端&am…

【GameFramework框架】二、GameFramework框架介绍

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录&#xff1a; https://blog.csdn.net/q7…

【C++】类和对象(2)

这篇博客继续学习类和对象~&#xff0c;主要介绍了类的6个默认成员函数。 目录 类的6个默认成员函数 构造函数 概念 特性 析构函数 概念 特性 拷贝构造函数 特性 赋值运算符重载 运算符重载 赋值运算符重载 前置和后置重载 日期类的实现 const成员 取地址及cons…

【数据结构与算法】(7)基础数据结构之双端队列的链表实现、环形数组实现示例讲解

目录 2.6 双端队列1) 概述2) 链表实现3) 数组实现习题E01. 二叉树 Z 字层序遍历-Leetcode 103 2.6 双端队列 1) 概述 双端队列、队列、栈对比 定义特点队列一端删除&#xff08;头&#xff09;另一端添加&#xff08;尾&#xff09;First In First Out栈一端删除和添加&…

html2canvas 截图功能使用 VUE

html2canvas 是一个 JavaScript 库&#xff0c;可以将网页内容转换为 Canvas 元素&#xff0c;并生成图像或 PDF 文件。使用 html2canvas&#xff0c;你可以在客户端将网页的内容截图&#xff0c;并将其作为图像或 PDF 文件保存或分享。 以下是一些 html2canvas 库的特点和用途…

一,凸包-----8,Graham Scan:实例

这个是个一般情况 1&#xff0c;初始化 如上图所示&#xff0c;按照先下后左的方式&#xff0c;先确定第一个极点1&#xff0c;然后以1为顶点按照角度排序&#xff0c;将1和最小的角度2放入S栈&#xff0c;将3-8按照角度从大到小压入T栈。 2&#xff0c; 从S栈的栈顶元素2和…

属性“xxxx”在类型“ArrayConstructor”上不存在。是否需要更改目标库? 请尝试将 “lib” 编译器选项更改为“es2015”或更高版本。

使用vscode编写vue&#xff0c;在使用elementUI时&#xff0c;发现代码中的form报错如下&#xff1a; 属性“form”在类型“ArrayConstructor”上不存在。是否需要更改目标库? 请尝试将 “lib” 编译器选项更改为“es2015”或更高版本。 解决方法&#xff1a; 打开jsconfig.…

迷你型洗衣机好用吗?口碑好的小型洗衣机推荐

不得不说洗衣机的发明解放了我们的双手&#xff0c;而我们从小到大就有这个意识&#xff0c;贴身衣物不可以和普通的衣服一起丢进去洗衣机一起&#xff0c;而内衣裤上不仅有肉眼看见的污渍还有手上根本无法消灭的细菌&#xff0c;但是有一款专门可以将衣物上的细菌杀除的内衣洗…