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

2024-02-03 10:44

本文主要是介绍在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

这篇关于在bash或脚本中,如何并行执行命令或任务(命令行、parallel、make)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/673905

相关文章

nginx启动命令和默认配置文件的使用

《nginx启动命令和默认配置文件的使用》:本文主要介绍nginx启动命令和默认配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录常见命令nginx.conf配置文件location匹配规则图片服务器总结常见命令# 默认配置文件启动./nginx

SQLite3命令行工具最佳实践指南

《SQLite3命令行工具最佳实践指南》SQLite3是轻量级嵌入式数据库,无需服务器支持,具备ACID事务与跨平台特性,适用于小型项目和学习,sqlite3.exe作为命令行工具,支持SQL执行、数... 目录1. SQLite3简介和特点2. sqlite3.exe使用概述2.1 sqlite3.exe

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java -jar命令如何运行外部依赖JAR包

《Java-jar命令如何运行外部依赖JAR包》在Java应用部署中,java-jar命令是启动可执行JAR包的标准方式,但当应用需要依赖外部JAR文件时,直接使用java-jar会面临类加载困... 目录引言:外部依赖JAR的必要性一、问题本质:类加载机制的限制1. Java -jar的默认行为2. 类加

git stash命令基本用法详解

《gitstash命令基本用法详解》gitstash是Git中一个非常有用的命令,它可以临时保存当前工作区的修改,让你可以切换到其他分支或者处理其他任务,而不需要提交这些还未完成的修改,这篇文章主要... 目录一、基本用法1. 保存当前修改(包括暂存区和工作区的内容)2. 查看保存了哪些 stash3. 恢

java -jar命令运行 jar包时运行外部依赖jar包的场景分析

《java-jar命令运行jar包时运行外部依赖jar包的场景分析》:本文主要介绍java-jar命令运行jar包时运行外部依赖jar包的场景分析,本文给大家介绍的非常详细,对大家的学习或工作... 目录Java -jar命令运行 jar包时如何运行外部依赖jar包场景:解决:方法一、启动参数添加: -Xb

Linux基础命令@grep、wc、管道符的使用详解

《Linux基础命令@grep、wc、管道符的使用详解》:本文主要介绍Linux基础命令@grep、wc、管道符的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录grep概念语法作用演示一演示二演示三,带选项 -nwc概念语法作用wc,不带选项-c,统计字节数-

MySQL的ALTER TABLE命令的使用解读

《MySQL的ALTERTABLE命令的使用解读》:本文主要介绍MySQL的ALTERTABLE命令的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、查看所建表的编China编程码格式2、修改表的编码格式3、修改列队数据类型4、添加列5、修改列的位置5.1、把列