shell 多线程

本文介绍了在Linux Shell中通过命名管道(fifo)实现多线程执行程序的示例,详细展示了如何控制后台进程的数量并保证任务执行的顺序。通过不同情况的代码对比,展示了如何有效地管理和控制进程的并发执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注意下面注释中带“>>>>>”的位置

 

情况1:

#!/bin/bash
temp_fifo_file=$$.info        #以当前进程号,为临时管道取名
mkfifo $temp_fifo_file        #创建临时管道
exec 6<>$temp_fifo_file       #创建标识为6,可以对管道进行读写
rm $temp_fifo_file            #清空管道内容
 
function f_sleep              
{
  sleep 2

 
temp_thread=2                 #进程数
 
for ((i=0;i<temp_thread;i++)) #为进程创建相应的占位
do
  echo                        #每个echo输出一个回车,为每个进程创建一个占位
done >&6                      #将占位信息写入标识为6的管道
 
for ((i=0;i<6;i++))          
do
  read                        #获取标识为6的占位
  {
    f_sleep
    echo $$,$i,`date`
    sleep 5
    echo $$,$i,`date`
    echo >&6                  #>>>>>当任务执行完后,会释放管道占位,所以补充一个占位
  }&                          #>>>>>在后台执行{}中的任务
done <&6                      #将标识为6的管道作为标准输入
 
wait                          #等待所有任务完成
exec 6>&-                     #关闭标识为6的管道
> date ; ./thread_1.sh
Tue Jun 19 17:12:36 TAIST 2012
4032,0,Tue Jun 19 17:12:38 TAIST 2012
4032,1,Tue Jun 19 17:12:38 TAIST 2012
4032,0,Tue Jun 19 17:12:43 TAIST 2012
4032,1,Tue Jun 19 17:12:43 TAIST 2012
4032,2,Tue Jun 19 17:12:45 TAIST 2012
4032,3,Tue Jun 19 17:12:45 TAIST 2012
4032,2,Tue Jun 19 17:12:50 TAIST 2012
4032,3,Tue Jun 19 17:12:50 TAIST 2012
4032,4,Tue Jun 19 17:12:52 TAIST 2012
4032,5,Tue Jun 19 17:12:52 TAIST 2012
4032,4,Tue Jun 19 17:12:57 TAIST 2012
4032,5,Tue Jun 19 17:12:57 TAIST 2012
 
21s

 情况2:

#!/bin/bash
temp_fifo_file=$$.info        #以当前进程号,为临时管道取名
mkfifo $temp_fifo_file        #创建临时管道
exec 6<>$temp_fifo_file       #创建标识为6,可以对管道进行读写
rm $temp_fifo_file            #清空管道内容
 
function f_sleep              
{
  sleep 2

 
temp_thread=2                 #进程数
 
for ((i=0;i<temp_thread;i++)) #为进程创建相应的占位
do
  echo                        #每个echo输出一个回车,为每个进程创建一个占位
done >&6                      #将占位信息写入标识为6的管道
 
for ((i=0;i<6;i++))          
do
  read                        #获取标识为6的占位
  {
    f_sleep
    echo $$,$i,`date`
  }&                          #>>>>>在后台执行{}中的任务
  sleep 5
  echo $$,$i,`date`
  echo >&6                    #>>>>>当任务执行完后,会释放管道占位,所以补充一个占位
done <&6                      #将标识为6的管道作为标准输入
 
wait                          #等待所有任务完成
exec 6>&-                     #关闭标识为6的管道
> date ; ./thread_1.sh
Tue Jun 19 17:18:28 TAIST 2012
6288,0,Tue Jun 19 17:18:30 TAIST 2012
6288,0,Tue Jun 19 17:18:33 TAIST 2012
6288,1,Tue Jun 19 17:18:35 TAIST 2012
6288,1,Tue Jun 19 17:18:38 TAIST 2012
6288,2,Tue Jun 19 17:18:40 TAIST 2012
6288,2,Tue Jun 19 17:18:43 TAIST 2012
6288,3,Tue Jun 19 17:18:45 TAIST 2012
6288,3,Tue Jun 19 17:18:48 TAIST 2012
6288,4,Tue Jun 19 17:18:50 TAIST 2012
6288,4,Tue Jun 19 17:18:53 TAIST 2012
6288,5,Tue Jun 19 17:18:55 TAIST 2012
6288,5,Tue Jun 19 17:18:58 TAIST 2012
 
30s

 情况3:

#!/bin/bash
temp_fifo_file=$$.info        #以当前进程号,为临时管道取名
mkfifo $temp_fifo_file        #创建临时管道
exec 6<>$temp_fifo_file       #创建标识为6,可以对管道进行读写
rm $temp_fifo_file            #清空管道内容
 
function f_sleep              
{
  sleep 2
  echo >&6                    #>>>>>当任务执行完后,会释放管道占位,所以补充一个占位

 
temp_thread=2                 #进程数
 
for ((i=0;i<temp_thread;i++)) #为进程创建相应的占位
do
  echo                        #每个echo输出一个回车,为每个进程创建一个占位
done >&6                      #将占位信息写入标识为6的管道
 
for ((i=0;i<6;i++))          
do
  read                        #获取标识为6的占位
  {
    f_sleep
    echo $$,$i,`date`
  }&                          #>>>>>在后台执行{}中的任务
  sleep 5
  echo $$,$i,`date`
done <&6                      #将标识为6的管道作为标准输入
 
wait                          #等待所有任务完成
exec 6>&-                     #关闭标识为6的管道
> date ; ./thread_1.sh
Tue Jun 19 17:17:06 TAIST 2012
5777,0,Tue Jun 19 17:17:08 TAIST 2012
5777,0,Tue Jun 19 17:17:11 TAIST 2012
5777,1,Tue Jun 19 17:17:13 TAIST 2012
5777,1,Tue Jun 19 17:17:16 TAIST 2012
5777,2,Tue Jun 19 17:17:18 TAIST 2012
5777,2,Tue Jun 19 17:17:21 TAIST 2012
5777,3,Tue Jun 19 17:17:23 TAIST 2012
5777,3,Tue Jun 19 17:17:26 TAIST 2012
5777,4,Tue Jun 19 17:17:28 TAIST 2012
5777,4,Tue Jun 19 17:17:31 TAIST 2012
5777,5,Tue Jun 19 17:17:33 TAIST 2012
5777,5,Tue Jun 19 17:17:36 TAIST 2012
 
30s

 情况4:

#!/bin/bash
temp_fifo_file=$$.info        #以当前进程号,为临时管道取名
mkfifo $temp_fifo_file        #创建临时管道
exec 6<>$temp_fifo_file       #创建标识为6,可以对管道进行读写
rm $temp_fifo_file            #清空管道内容
 
function f_sleep              
{
  sleep 2
  echo >&6                    #>>>>>当任务执行完后,会释放管道占位,所以补充一个占位

 
temp_thread=2                 #进程数
 
for ((i=0;i<temp_thread;i++)) #为进程创建相应的占位
do
  echo                        #每个echo输出一个回车,为每个进程创建一个占位
done >&6                      #将占位信息写入标识为6的管道
 
for ((i=0;i<6;i++))          
do
  read                        #获取标识为6的占位
  {
    f_sleep
    echo $$,$i,`date`
    sleep 5
    echo $$,$i,`date`
  }&                          #>>>>>在后台执行{}中的任务
done <&6                      #将标识为6的管道作为标准输入
 
wait                          #等待所有任务完成
exec 6>&-                     #关闭标识为6的管道
> date ; ./thread_1.sh
Tue Jun 19 17:16:11 TAIST 2012
5367,0,Tue Jun 19 17:16:13 TAIST 2012
5367,1,Tue Jun 19 17:16:13 TAIST 2012
5367,3,Tue Jun 19 17:16:15 TAIST 2012
5367,2,Tue Jun 19 17:16:15 TAIST 2012
5367,4,Tue Jun 19 17:16:17 TAIST 2012
5367,5,Tue Jun 19 17:16:17 TAIST 2012
5367,0,Tue Jun 19 17:16:18 TAIST 2012
5367,1,Tue Jun 19 17:16:18 TAIST 2012
5367,3,Tue Jun 19 17:16:20 TAIST 2012
5367,2,Tue Jun 19 17:16:20 TAIST 2012
5367,4,Tue Jun 19 17:16:22 TAIST 2012
5367,5,Tue Jun 19 17:16:22 TAIST 2012
 
11s
 
--------------------- 
作者:wqq_721 
来源:优快云 
原文:https://blog.youkuaiyun.com/wqq_721/article/details/7968099 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

 

 

 

linux shell 多线程执行程序

Shell中并没有真正意义的多线程,要实现多线程可以启动多个后端进程,最大程度利用cpu性能。

直接看代码示例吧。

(1) 顺序执行的代码

 1 #!/bin/bash
 2 date
 3 for i in `seq 1 5`
 4 do
 5 {
 6     echo "sleep 5"
 7     sleep 5
 8 }
 9 done
10 date 

输出:

Sat Nov 19 09:21:51 CST 2016
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
Sat Nov 19 09:22:16 CST 2016

(2) 并行代码

使用'&'+wait 实现“多进程”实现

按 Ctrl+C 复制代码

 

按 Ctrl+C 复制代码

输出:

Sat Nov 19 09:25:07 CST 2016
sleep 5
sleep 5
sleep 5
sleep 5
sleep 5
Sat Nov 19 09:25:12 CST 2016

 (3) 对于大量处理任务如何实现启动后台进程的数量可控?

  简单的方法可以使用2层for/while循环实现,每次wait内层循环的多个后台程序执行完成

  但是这种方式的问题是,如果内层循环有“慢节点”可能导致整个任务的执行执行时间长。

  更高级的实现可以看(4)

(4) 使用命名管道(fifo)实现每次启动后台进程数量可控。 

 

参考:https://www.cnblogs.com/xudong-bupt/p/6079849.html

&lt;think&gt;好的,我现在需要向用户介绍Shell中的多线程执行。首先,我需要明确用户的问题是什么,他们可能想了解如何在Shell脚本中实现并发执行任务,以提高效率。接下来,我得考虑Shell本身是否支持多线程,或者用户是否指的是多进程的方式,因为Shell通常使用子进程来模拟并发。 首先,我应该解释Shell本身并不支持真正的多线程,比如像Java或Python那样的线程模型。Shell脚本默认是顺序执行的,但可以通过一些方法实现并发,比如使用后台运行(&amp;)和wait命令来控制多个进程的并行执行。这实际上是多进程的方式,但在效果上类似于多线程,能够同时处理多个任务。 接下来,我需要介绍具体的实现方法。例如,使用&amp;将命令放到后台运行,这样脚本不会等待该命令完成就继续执行下一个命令。然后,使用wait命令等待所有后台任务完成,这样可以确保在需要的时候同步各进程的结果。 可能还需要提到如何控制并发数量,比如使用命名管道(mkfifo)或类似的技术来创建队列,限制同时运行的进程数目,避免系统资源被耗尽。例如,使用循环和计数器来启动一定数量的后台任务,然后等待其中一部分完成后再启动新的任务,从而控制并发度。 另外,需要提到一些常见的陷阱,比如资源竞争、输出混乱的问题。当多个进程同时向标准输出写入时,输出可能会交错在一起,导致难以阅读。这时候可以考虑将每个进程的输出重定向到不同的文件,或者使用工具如GNU parallel来处理复杂的并行任务,它能够更好地管理输出和资源分配。 还有,GNU parallel是一个强大的工具,可以简化并行处理,用户可能想知道这个工具的基本用法,比如如何用它来并行执行命令,处理输入列表,控制任务数量等。但用户的问题是关于Shell本身的多线程,所以可能需要简要提及这个工具作为扩展。 在结构上,应该先介绍基本概念,然后逐步讲解实现方法,从简单的后台执行到控制并发数量,再到处理输出和推荐工具。同时,需要提供示例代码,帮助用户更好地理解。例如,展示一个使用循环和后台任务来并发处理文件的例子,或者使用队列机制限制并发数的例子。 还要注意语法正确性,在示例中使用正确的Shell语法,比如使用圆括号启动子shell,或者使用wait的正确位置。同时,可能需要提醒用户注意不同Shell之间的差异,比如Bash和Dash可能在语法上有所不同,建议使用Bash以获得更好的功能支持。 最后,总结Shell多线程(实际是多进程)的优缺点,适用场景,以及更高效的工具推荐,比如GNU parallel或者xargs的-P参数,这些都能帮助用户更好地处理并行任务。需要确保回答结构清晰,步骤明确,让用户能够逐步理解和应用这些方法。&lt;/think&gt;在Shell脚本中实现多线程(实际是**多进程并发**)的步骤如下: --- ### 一、基本概念 Shell本身不支持真正的多线程(Thread),但可通过启动多个子进程模拟并行。常用方法: - `&amp;` 符号:将命令放入后台执行 - `wait` 命令:等待所有后台任务完成 - 资源控制:避免过度占用CPU/内存 --- ### 二、基础实现 #### 示例1:简单并行任务 ```bash #!/bin/bash # 启动3个后台任务 task1() { sleep 2; echo &quot;任务1完成&quot;; } task2() { sleep 1; echo &quot;任务2完成&quot;; } task3() { sleep 3; echo &quot;任务3完成&quot;; } task1 &amp; task2 &amp; task3 &amp; wait # 等待所有后台任务结束 echo &quot;所有任务完成&quot; ``` #### 输出结果: ``` 任务2完成 任务1完成 任务3完成 所有任务完成 ``` --- ### 三、控制并发数量 #### 方法1:循环计数器 ```bash #!/bin/bash max_workers=2 # 最大并发数 counter=0 for i in {1..5}; do ( echo &quot;任务 $i 开始&quot; sleep $((RANDOM%3+1)) echo &quot;任务 $i 完成&quot; ) &amp; ((counter++)) if ((counter == max_workers)); then wait # 等待当前批次任务完成 counter=0 fi done wait echo &quot;全部任务结束&quot; ``` #### 方法2:使用命名管道(更精准控制) ```bash #!/bin/bash concurrent=3 tmp_fifo=&quot;/tmp/$$.fifo&quot; mkfifo $tmp_fifo exec 6&lt;&gt;$tmp_fifo rm -f $tmp_fifo for ((i=0; i&lt;$concurrent; i++)); do echo &gt;&amp;6 # 初始化管道令牌 done for i in {1..10}; do read -u6 # 获取令牌 { echo &quot;处理任务 $i&quot; sleep 1 echo &gt;&amp;6 # 归还令牌 } &amp; done wait exec 6&gt;&amp;- echo &quot;执行完毕&quot; ``` --- ### 四、注意事项 1. **输出混乱问题** 各子进程的输出可能交错,可通过重定向解决: ```bash task &gt; output_$i.log 2&gt;&amp;1 &amp; ``` 2. **资源监控** 使用 `top` 或 `htop` 观察CPU/内存占用 3. **任务隔离** 每个子进程是独立环境,变量需显式传递 --- ### 五、高级工具推荐 1. **GNU Parallel** ```bash seq 10 | parallel -j 4 &quot;echo Processing {}; sleep 1&quot; ``` 2. **xargs 的 -P 参数** ```bash seq 10 | xargs -I{} -P4 sh -c &#39;echo 处理{}; sleep 1&#39; ``` --- ### 六、适用场景 - 批量文件处理(如压缩/格式转换) - API并发请求测试 - 日志并行分析 --- 通过合理控制并发数,Shell脚本可实现效率提升数倍至数十倍,但需注意避免过度并发导致系统负载过高。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值