简体   繁体   English

多线程Bash如果声明

[英]Multithreading Bash If Statements

What is the correct way to multithread independent if statements in a bash script? 在bash脚本中多线程独立if语句的正确方法是什么? Is it best to place the & after code contained in the if or after the expression? 难道最好将&在所包含的代码之后if还是表达后?

For an & after the expression, it makes sense to continue threading as necessary if the if contains a large block of code. 对于表达式之后的& ,如果if包含大块代码, if根据需要继续进行线程化是有意义的。 But should one line of code also end with & ? 但是,如果一行代码也以&结尾?

After the expression: 表达后:

if [ expression ] &
  then
    #task
fi

After the task: 完成任务后:

if [ expression ]
  then
    #task &
fi


Imagine 3 if statements that all perform tasks independent of each other, how does the execution work with the different placement of the & ? 想象一下, if所有执行任务的语句彼此独立,那么执行如何与&的不同位置一起工作? From what I understand, if placed after the expression, all 3 expressions start (basically) simultaneously and so do the 3 tasks. 根据我的理解,如果放在表达式之后,所有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 placed after the task code, the first if would be evaluated and only as the first task begins would the 2nd if be evaluated. 如果放在任务代码之后,第一if将被评估,仅作为第一个任务开始将2号if进行评估。 The tasks are more staggered than simultaneous. 这些任务比同步更加错开。

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

The expressions cannot be combined to do threading inside the if such as: 表达式不能组合在if进行线程化,例如:

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

If you want each if condition to execute within the context of its respective "thread" (actually subshell process), then I think the thing to do is put the & after the closing fi statement for each if . 如果你希望每个if条件在它各自的“线程”(实际上是子shell进程)的上下文中执行,那么我认为要做的是将每个if的结束fi语句后面的& Then the evaluation of each if expression, along with conditional code wiil occur entirely within the context of its own "thread". 然后,每个if表达式的评估以及条件代码将完全在其自己的“线程”的上下文中发生。

For example: 例如:

#/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

Output from each "thread" is interleaved as expected: 每个“线程”的输出按预期交错:

1
a
2
b
3
c

Note in all cases with & , these are actually processes (created with fork() ) and not threads (created with pthread_create() ). 注意在所有情况下使用& ,这些实际上是进程(使用fork()创建)而不是线程(使用pthread_create()创建)。 See Multithreading in Bash . 请参阅Bash中的多线程 You can test this by creating a variable, eg n=0 before the "threads" are started. 您可以通过创建变量来测试这一点,例如在“线程”启动之前n=0 Then in one thread increment n and echo $n in all threads. 然后在一个线程中增加n并在所有线程中回显$ n。 You'll see each "thread" gets its own copy of n - n will have different values in the incrementing and non-incrementing threads. 您将看到每个“线程”获得自己的n - n副本将在递增和非递增线程中具有不同的值。 fork() creates a new process copy (including independent copies of variables); fork()创建一个新的流程副本(包括变量的独立副本); pthread_create() doesn't. pthread_create()没有。

Placing the & after the if will only background the evaluation of the conditional expression ; 放置&if将只背景条件表达式的评估; [ is actually an alias for the test command, and that is what will be backgrouded, and not the task. [实际上是test命令的别名,这将是背景,而不是任务。

Placing the & after the task will background the task. 在任务之后放置&后台将完成任务。 The degree to which the tasks are staggered rather than simultaneous depends on the relative time needed to evaluate expr1 compared to the time needed to perform task1 在何种程度上的任务是交错的,而不是同时取决于评估所需要的相对时间expr1比执行所需的时间task1

See the following script: 请参阅以下脚本:

#!/bin/bash

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

it takes 30 seconds to run 它需要30秒才能运行

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

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

and you see that the backgrounded task is [ 1 ] , not sleep . 你看到后台任务是[ 1 ] ,而不是sleep Note that is is meaningless as explained by @chepner. 注意,如@chepner所解释的那样没有意义。

Now the other case: 现在另一个案例:

#!/bin/bash

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

gives: 得到:

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

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

It only takes 10 seconds ; 它只需要10秒钟; all the sleeps are simultaneous as they are being backgrounded. 所有的sleeps是同时的,因为它们是背景的。

Last option as described by @DigitalTrauma: @DigitalTrauma描述的最后一个选项:

#!/bin/bash

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

Then the whole if statement is backgrounded, ie both the evaluation of exprN and of taskN 然后整个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

giving the expected 10 seconds running time 给出预期的10秒运行时间

Compare 相比

if false
then
  echo "condition true"
fi

with

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

A command terminated by & exits immediately with status 0, so the if branch is taken regardless of what the background process eventually returns. 命令&以状态0立即退出&退出,因此无论后台进程最终返回什么,都会执行if分支。 It doesn't make sense to put a command that unconditionally succeeds in the command list of an if statement. 将无条件成功的命令放在if语句的命令列表中是if You have to let it complete so the body can be correctly (conditionally) executed. 你必须让它完整,以便正确(有条件地)执行身体。

the answers so far rely on using spawning 3 and waiting for all 3 to complete before starting again. 到目前为止,答案依赖于使用产卵3并等待所有3完成再开始之前。

a "better" way in bash is using the jobs command like so bash中的“更好”方式就是使用jobs命令

jobs|wc -l and then looping with a small sleep command like so jobs|wc -l然后使用像这样的小睡眠命令循环

(not tested code) (未测试代码)

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

    expression &
    fi
    sleep 10;

done

that will allow all 3 "threads" to be filled without waiting for all 3 to complete before refilling 这将允许所有3个“线程”被填充,而无需等待所有3个完成再填充之前完成

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM