
正文
linux并发执行命令 linux shell并发执行
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
在Linux系统中使用Shell实现多线程运行任务(多任务并发执行) 2022-05-30
最近,有一批任务需要把两批linux并发执行命令的fastq合并到一起并压缩成一个fastq文件才能继续往下做,由于存储空间有限又不能直接全部跑上,只能按样本逐个分批跑。众所周知,一般fastq是成对存在的,所需要对read1和read2分别合并一次,然而这次任务的fastq文件比较大,合并然后压缩一次需要1天左右,那对于一组fastq就要2-3天,这也太耗时间了,所以我在想能不能read1和read2 同时跑上,这就可以节省一半的时间了。
平时也能遇到很多类似的任务,特别是在进程数有限的情况下,如果这些小任务单独占用一个进程,而任务很多就很耗时间,如果能在一个进程下实现多个线程并行执行,就能大大提高运行效率。关于进程和线程的知识可以参考知乎的这篇文章【 Shell“ 多线程”,提高工作效率 】,整理的也比较有条理,能比较容易读懂。
当然,某些博主也写过类似的文章,例如这篇【 shell后台限制多并发控制后台任务强度进行文件拷贝 】但是实在是太高深莫测了,看不懂,一时半会儿也学不会。本文将示例Shell实现多线程的简单版本,其实不用太复杂。
其实只需要两个步骤, 第一步是给需要并行运行的命令行在结尾加上"",代表放到后台运行,第二步是在在所有并行任务的后面加上一句“wait”,意思是等所有通过“”放到后台运行的任务跑完后再继续执行后面的任务 ,这些就能实现所有带有“”的行并行执行了。
看完脚本是不是觉得很简单linux并发执行命令?
上面的脚本适合并行任务少的,可以手动加和wait,但是如果有几十个甚至上百个的小任务就比较麻烦了。但不用担心,可以写个循环,批量运行。
循环的结果也是跟上面类似的,只是多了个循环结构。
如果需要执行的任务只有一行,可以把大括号去掉。
关于for和while的循环可以查看之前的文章【 Shell常用循环示例(for和while批量处理)2022-05-25 】
需要注意的是多线程并行还是需要有限制的,毕竟都是在一个进程里运行,如果线程太多了会卡顿的,建议控制在100个以内,当然还有毕竟高级和复杂的方法可以实现限制。因为上面的脚本已经够我用了,没继续往下学,以后可以再补充。
相关问答
Q1: linux内核中造成并发执行的原因是什么
linux中内核并发机制也就是同步机制产生的原因,总的来说可归纳为一下4点:
l 中断——中断几乎可以在任何时刻异步发生,也就可能随时打断当前正在执行的代码。
2 睡眠及与用户空间的同步——在内核执行的进程可能会睡眠,这就会唤醒调度程序,从而导致调度一个新的用户进程执行。
3 对称多处理——两个或多个处理器可以同时执行代码。
4内核抢占——因为内核具有抢占性,所以内核中的任务可能会被另一任务抢占(在2.6内核引进的新能力)。
Q2: linux cron 如果设置了同一时间的多个python脚本任务,它们会并发执行还是依次执行?
我的观点为是这样的.
程序应该是并发执行的.
但是,执行的顺序,应该是随机的.也就是说test1,pytest3,pytest3,py不一定哪个最先开始.
Q3: 如何在linux下验证两个线程是否并发执行的代码 如线程A与线程B
线程。对于计算机微处理器而言linux并发执行命令,程序只是一组编译过的机器代码,可以执行相关的数据计算与操作,这些代码由一条条的指令组成,每一个代码组就是一条线程。
现有主流CPU为x86架构,每次只能执行一条线程,即单线程。单CPU系统中,在执行指令的时候,CPU先找出相应指令所在的内存位置,执行下一条指令,再转换到另一个位置,在同一时间内CPU只能对应一个指令。线程可以中断,并把中间结果暂存在另一个特殊位置(堆栈),不同的线程可以交叉运行,实现多任务,但每次运行的线程仍然仅有一条,千万不要把多任务和多线程混淆linux并发执行命令了。
既然一个CPU是单线程,那么两个CPU自然就可以双线程啦,如此类推,就会出现四路、八路系统。但双处理器系统的性能并不能达到单处理器的两倍,通常只有33%的性能增益。
为了提高CPU的性能,厂商通常采用增加工作频率和缓存容量的方法来提升速度,但这是治标不治本的方法,CPU只提高了速度,其内在潜力依然未能完全发挥,CPU的执行单元没有被充分利用,于是设计者就在CPU中加入两个逻辑处理单元,同时管理CPU的全部资源,直接提高CPU内核的工作效率。
超线程技术就是利用特殊的硬件指令,把两个逻辑内核模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,从而兼容多线程操作系统和软件,提高处理器的性能。操作系统或者应用软件的多线程可以同时运行于一个HTT处理器上,两个逻辑处理器共享一组处理器执行单元,并行完成加、乘、负载等操作。
如何提升工作效率
那么,超线程技术是如何提高CPU性能的呢linux并发执行命令?
我们知道,CPU由很多执行单元组成(如整数运算单元、浮点运算单元和存储单元),这些执行单元无法同时工作,大多数时间有一半执行单元是处于空闲状态。例如,MS Office等商业软件主要使用整数运算单元和读写/存储单元,几乎不涉及浮点运算单元,3D渲染软件主要使用浮点运算单元,很少涉及整数运算单元,很明显,这种设计造成了很大的浪费。如P4处理器内部有7个执行单元,每个时钟周期内,约有2个执行单元工作,它们共执行两次操作,那么,其他5个单元完全没有用到。
为了解决这个问题,高端电脑采用了ILP(Instruction Level Parallelism,指令级平行运算)技术,可以同时执行多条指令,提高单CPU的效率。而x86架构只能让多个CPU来执行不同的线程,不过硬件成本增加了不少,于是超线程技术处理器的出现正式兼容两者的优势。
传统处理器和支持超线程处理器在指令执行上的对比,参见^42030101a^1、^42030101b^2、^42030101c^3。
从上面的对比图可以看出:采用了超线程技术后,处理器真正并行执行多个线程,从而在同一频率和缓存的基础上实现了提高系统性能的技术变革。
超线程技术对商用和家用电脑而言,除了全面提升系统性能以外,还增加系统平台所能支持用户的数量,大幅降低系统的反应潜伏时间(因为任务能被分为几个隔离的线程来同时执行),增加系统的指令执行数量,还有一点很关键的是,即使对于现有的IA-32体系软件它也能很好地兼容。因为,HTT处理器还提供一个中断指令,在执行适合单处理器的任务时,暂停其中一个逻辑内核,让操作系统识别为单处理器,在执行适合多处理器的任务时,重新打开逻辑内核,利用HTT来增加整体效率。
软硬件支持与应用
支持超线程技术需软硬件的支持,硬件方面需要主板北桥芯片的支持。目前支持超线程技术的北桥有850E、845E、845G(B版本)、845GV、845GE、845PE,以及未来英特尔能支持到533MHz FSB的北桥都将支持超线程技术。支持400MHz FSB的北桥是不支持超线程技术的,支持超线程技术的处理器配合这样的北桥使用时,只能作为传统的处理器使用。
超线程技术还需要主板对CPU的电源支持,需要主板能提供给处理器高达70A的电流,否则系统可能不能长期稳定工作。除此之处还需要主板BIOS的支持,需要BIOS加入特定的支持HTT处理器的代码。当BIOS检测到是超线程处理器时,在BIOS设置菜单中出现CPU Hyper-Threading(Enabled or Disabled)的选项。
超线程技术还需要操作系统的支持。目前支持超线程技术的有Windows XP和Linux 2.4.X。这不同于传统的处理器安装的Windows XP,使用超线程技术的处理器安装完Windows XP后在设备管理器中能显示有两个处理器和ACPI Multiprocessor PC。
当然你的处理器必须支持超线程技术。从即将于下个月发布的3.06GHz P4开始,英特尔的处理器都将支持超线程技术。
这里笔者以QDI的P2E 333和P8 333这两款主板为例,它们的北桥芯片分别是英特尔845PE和845GE,支持533MHz FSB和DDR333,支持处理器超线程技术linux并发执行命令;主板的CPU供电电源模块符合英特尔Northwood FMB2标准,能提供70A的电流;在测试中使用超线程处理器3.06GHz P4 CPU(实验样品)开机后,进入BIOS中出现CPU Hyper-Threading的选项。
安装Windows XP后,设备管理器出现两个处理器和ACPI Multiprocessor PC,在任务管理器中出现两个CPU实时使用率的图标,如^42030101d^4:
笔者对开启和关闭CPU Hyper-Threading功能的测试中,发现启用超线程技术能使系统性能提高近20%左右。
另外,站长团上有产品团购,便宜有保证
Q4: Linux下的并行神器——parallel
GNU Parallel的输入源支持文件、命令行和标准输入(stdin或pipe)。
当然,若不想像上面那样进行组合,可使用 --xapply 参数从每一个源获取一个参数(或文件一行),这个参数有些类似R中的函数,具有广播作用——如果其中一个输入源的长度比较短,它的值会被重复。
GNU Parallel可以通过 --arg-sep 和 --arg-file-sep 指定分隔符替代 ::: 或 ::::,当这两个符号被其它命令占用的时候会特别有用。
GNU Parallel默认把一行做为一个参数:使用 \n 做为参数定界符。可以使用 -d 改变:
GNU Parallel支持通过 -E 参数指定一个值做为结束标志:
GNU Parallel使用 --no-run-if-empty 来跳过空行:
如果parallel之后没有给定命令,那么这些参数会被当做命令:
此外,命令还可以是一个脚本文件,一个二进制可执行文件或一个bash的函数(须用 export -f 导出函数)
GNU Parallel支持多种替换字符串,默认使用 {},使用 -I 改变替换字符串符号 {}。其最常见的字符串替换包括以下几种: {.} ,去掉扩展名; {/} ,去掉路径,只保留文件名; {//} ,只保留路径; {/.} ,同时去掉路径和扩展名; {#} ,输出任务编号。同时对于每一个字符串替换都可以自己指定符号: -I 对应 {} ; --extensionreplace 替换 {.} ; --basenamereplace 替换 {/} ; --dirnamereplace 替换 {//} ; --basenameextensionreplace 替换 {/.} ; --seqreplace 替换 {#} 。
同时,如果有多个输入源时,可以通过 {编号} 指定某一个输入源的参数:
使用 --header 把每一行输入中的第一个值做为参数名。
使用 --colsep 把文件中的行切分为列,做为输入参数。
--xargs 会在一行中输入尽可能多的参数(与参数字符串长度有关),通过 -s 可指定一行中参数的上限。
为了获得更好的并发性,GNU Parallel会在文件读取结束后再分发参数。
GNU Parallel 在读取完最后一个参数之后,才开始第二个任务,此时会把所有的参数平均分配到4个任务(如果指定了4个任务)。
第一个任务与上面使用 --xargs 的例子一样,但是第二个任务会被平均的分成4个任务,最终一共5个任务。(奇怪的是我的结果与官网教程的结果不一样)
替换字符串可以是输出字符的一部分,使用 -m 参数表示每个job不重复输出“背景”(context), -X 则与 -m 相反,会重复输出“背景文本”,具体通过下面几个例子进行理解:
使用 -N 限制每行参数的个数,其中 -N0 表示一次只读取一个参数,且不输入这个参数(作为计数器来使用)。
如果命令行中包含特殊字符,就需要使用引号保护起来。
perl脚本 'print "@ARGV\n"' 与linux的 echo 的功能一样。
使用GNU Parallel运行这条命令的时候,perl命令需要用引号包起来,也可以使用 -q 保护perl命令:
使用 --trim 去除参数两头的空格:
使用 --tag 以参数做为输出前缀,使用 --tagstring 修改输出前缀:
--dryrun 作用类似于echo:
--verbose 则在运行之前先打印命令:
一般来说,GNU Parallel 会延迟输出,直到一组命令执行完成。使用 --ungroup ,可立刻打印输出已完成部分。
使用 --ungroup 会很快,但会导致输出错乱,一个任务的行输出可能会被另一个任务的输出截断。像上例所示,第二行输出混合了两个任务: '4-middle' '2-start'。使用 --linebuffer 避免这个问题(稍慢一点):
强制使输出与参数保持顺序 --keep-order/-k :
GNU Parallel可以把每一个任务的输出保存到文件中,临时文件默认保存在 /tmp 中,可以使用 --tmpdir改变(或者修改 $TMPDIR):
输出文件可以有结构的保存 --results ,输出文件不仅包含标准输出(stdout)也会包含标准错误输出(stderr):
在使用多个变量的时候会显示很有用:
使用 --jobs/-j 指定并行任务数。
通过使用 --interactive 在一个任务执行之前让用户决定是否执行。
当job有大量的IO操作时,为避免 “惊群效应” ,可使用 --delay 参数指定各个job开始的时间间隔。
若已知任务超过一定时间未反应则为失败则可以通过 --timeout 指定等待时间避免无谓的等待。GNU parallel能计算所有任务运行时间的中位数,因此可以指定时间为中位数的倍数关系。
GNU parallel有多种方式可用来动态的显示任务进度信息,如:
使用 --joblog 参数能够生成各个任务的日志文件:
通过 --resume-failed 参数可以重新运行失败的任务; --retry-failed 的作用与 --resume-failed 类似,只是 --resume-failed 从命令行读取失败任务,而 --retry-failed 则是从日志文件中读取失败任务:
GNU parallel支持在某一情况下(如第一个失败或成功时,或者20%任务失败时)终止任务,终止任务又有两种类型,其一为立即终止(通过 --halt now 指定),杀死所有正在运行的任务并停止生成新的任务,其二为稍后终止(通过 --halt soon 指定),停止生成新任务并等待正在运行任务完成。
GNU parallel还支持在任务失败后重试运行 --retries :
关于终止信号的高级用法参考 官方入门文档 。
GNU parallel能够在开始一个新的任务前检查系统的负载情况防止过载(通过 --load 可指定负载),同时还能检查系统是否使用了交换空间(swap)(通过 --noswap 限制使用swap)。
同时,对于某些占用内存较多的程序,parallel会检查内存只有内存满足时才启动任务(通过 --memfree 指定需要内存大小),而且在启动任务后内存不够50%时会杀掉最新开始的任务,直到这个任务完成再重新开始那些杀死的任务。
还可以通过 --nice 来指定任务的优先级。
可使用 -S host 来进行远程登陆:
parallel -S username@$SERVER1 echo running on ::: username@$SERVER1
GNU parallel 文件传输使用的是rsync。
更多远程操作参见入门文档。
--pipe 参数使得我们可以将输入(stdin)分为多块(block),然后分配给多个任务多个cpu以达到负载均衡,最后的结果顺序与原始顺序一致。使用 --block 参数可以指定每块的大小,默认为1M。
如果不关心结果顺序,只想要快速的得到结果,可使用 --round-robin 参数。没有这个参数时每块文件都会启动一个命令,使用这个参数后会将这些文件块分配给job数任务(通过 --jobs 进行指定)。若想分配更为均匀还可同时指定 --block 参数。
参考:
官方文档
GNU Parallel指南
linux并发执行命令的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux shell并发执行、linux并发执行命令的信息别忘了在本站进行查找喔。







