多线程Bash如果声明

时间:2013-10-18 19:16:58

标签: linux multithreading bash unix

在bash脚本中多线程独立if语句的正确方法是什么?是否最好将&放在if或表达式后面的代码之后?

对于表达式之后的&,如果if包含大块代码,则根据需要继续进行线程化是有意义的。但是,如果一行代码也以&结束吗?

表达式之后:

if [ expression ] &
  then
    #task
fi

完成任务后:

if [ expression ]
  then
    #task &
fi


想象3个if语句都执行彼此独立的任务,执行如何与&的不同位置一起工作?根据我的理解,如果放在表达式之后,所有3个表达式(基本上)同时启动,3个任务也是如此。

#Thread 1         #Thread 2         #Thread 3
if [ expr1 ] &    if [ expr2 ] &    if [ expr3 ] &
  then              then              then
    task1            task2            task3
fi                fi                fi
wait

如果放在任务代码之后,将评估第一个if,并且仅在第一个任务开始时才评估第二个if。这些任务比同步更加错开。

#Thread 1         #Thread 2         #Thread 3
if [ expr1 ]
  then
    task1 &       if [ expr2 ]
fi                  then
                      task2 &       if [ expr3 ]
                  fi                  then
                                        task3 &
                                    fi
wait

表达式不能组合在if内进行线程处理,例如:

if [ combined expression ]
  then
    #task1 &
    #task2 &
    #task3 &
fi

4 个答案:

答案 0 :(得分:6)

如果你希望每个if条件在其各自的“线程”(实际上是子shell进程)的上下文中执行,那么我认为要做的是在结束后放置& {{ 1}}每个fi的语句。然后,每个if表达式的评估以及条件代码将完全在其自己的“线程”的上下文中发生。

例如:

if

每个“线程”的输出按预期交错:

#/bin/bash

if [ 1 ] 
  then
    for i1 in {1..3}; do echo $i1; sleep 1; done
fi &
if [ 1 ]
  then
    for i2 in {a..c}; do echo $i2; sleep 1; done
fi &
wait

注意在1 a 2 b 3 c 的所有情况下,这些实际上是进程(使用&创建)而不是线程(使用fork()创建)。见Multithreading in Bash。你可以通过创建一个变量来测试它,例如在“线程”启动之前pthread_create()。然后在一个线程中增加n并在所有线程中回显$ n。您将看到每个“线程”获得自己的n - n副本将在递增和非递增线程中具有不同的值。 n=0创建一个新的流程副本(包括变量的独立副本); fork()没有。

答案 1 :(得分:5)

&之后放置if只会影响条件表达式的评估; [实际上是test命令的别名,这就是要进行背景,而不是任务。

在任务之后放置&将为任务提供背景。任务交错而不是同步的程度取决于评估expr1与执行task1所需时间相比所需的相对时间

请参阅以下脚本:

#!/bin/bash

if [ 1 ] &
then
    sleep 10 
fi
if [ 1 ] &
then
    sleep 10 
fi
if [ 1 ] &
then
    sleep 10 
fi
wait

运行需要30秒

$ time . test.sh 
[3]   Done                    [ 1 ]
[3]   Done                    [ 1 ]
[3]   Done                    [ 1 ]

real    0m30.015s
user    0m0.003s
sys 0m0.012s

您发现后台任务是[ 1 ],而不是sleep。请注意,如@chepner所解释的那样没有意义。

现在是另一种情况:

#!/bin/bash

if [ 1 ] 
then
    sleep 10 &
fi
if [ 1 ] 
then
    sleep 10 &
fi
if [ 1 ] 
then
    sleep 10 &
fi
wait

给出:

[2]   Done                    sleep 10
[3]   Done                    sleep 10
[4]-  Done                    sleep 10

real    0m10.197s
user    0m0.003s
sys 0m0.014s

只需10秒钟;所有sleeps都是同时进行的,因为它们都是背景的。

@DigitalTrauma描述的最后一个选项:

#!/bin/bash

if [ 1 ] 
then
    sleep 10 
fi &
if [ 1 ]
then
    sleep 10 
fi &
if [ 1 ] 
then
    sleep 10
fi &
wait

然后整个if语句都是背景的,即对exprNtaskN的评估

[3]   Done                    if [ 1 ]; then
    sleep 10;
fi
[4]   Done                    if [ 1 ]; then
    sleep 10;
fi
[5]   Done                    if [ 1 ]; then
    sleep 10;
fi

real    0m10.017s
user    0m0.003s
sys 0m0.013s

给出预期的10秒运行时间

答案 2 :(得分:4)

比较

if false
then
  echo "condition true"
fi

if false &
then
  echo "condition ... true?"
fi

&终止的命令会立即退出,状态为0,因此无论后台进程最终返回什么,都会执行if分支。将无条件成功的命令放在if语句的命令列表中是没有意义的。你必须让它完整,以便正确(有条件地)执行身体。

答案 3 :(得分:0)

到目前为止,答案依赖于使用产卵3并等待所有3完成再开始。

bash中的“更好”方式是使用jobs命令,如此

jobs|wc -l然后使用像这样的小睡眠命令循环

(未经过测试的代码)

 while [  $COUNTER -lt 10 ]; do
if [[$(jobs | wc-l`) < 3 ]] then 

    expression &
    fi
    sleep 10;

done

这将允许填充所有3个“线程”而无需等待所有3个完成再填充