2013-10-18 27 views
7

多線程獨立if語句在bash腳本中的正確方法是什麼?將代碼包含在if之後或者在表達式之後放置&是否最好?多線程Bash如果語句

對於表達式後面的&,如果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 

回答

6

如果您想要執行每個if條件在其各自的「線程」(實際上是子shell過程)的上下文中,那麼我認爲要做的事情是在關閉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()創建)和不線程(使用pthread_create()創建)。見Multithreading in Bash。您可以通過創建一個變量來進行測試,例如n=0在「線程」啓動之前。然後在一個線程中增加n並在所有線程中回顯$ n。你會看到每個「線程」獲得它自己的副本n -n在遞增和非遞增線程中會有不同的值。 fork()創建一個新的進程副本(包括變量的獨立副本); pthread_create()沒有。

+0

在我的具體情況下,我認爲這很好他們是獨立的進程。當等待完成時,「等待」是否結束子進程? – Matt

+1

非常好,是的。等待所有子子進程完成。所以如果你在'wait'後面有更多的語句,那麼這些語句將不會執行,直到所有的子進程完成。如果你想等待一個特定的子進程結束,'wait'也可以帶一個PID或作業ID。您可以在使用'&'背景後,從內置的'$!'變量中獲取子進程的pid。 –

5

放置的if只會背景條件表達式的評估後&; [實際上是test命令的別名,這是後臺操作,而不是任務。

在任務完成後,將&放置在任務後面。在何種程度上的任務是交錯的,而不是同時取決於相比,執行task1

請參見下面的腳本所需要的時間來評估expr1所需要的相對時間:

#!/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語句中背景,即兩者的exprN評價和taskN

[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秒

4

比較

if false 
then 
    echo "condition true" 
fi 

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

通過&出口立即終止狀態爲0的命令,所以if分支無論什麼樣的後臺進程最終返回拍攝。將無條件成功的命令放在if語句的命令列表中是沒有意義的。您必須讓它完成,以便正確(有條件地)執行正文。

+0

我想知道會不會發生。我認爲'&'會繼續下一行代碼,但認爲下一行讀取是在'fi'之後。我認爲DigitalTrauma的答案仍然允許評估。 – Matt

+0

是的,他的回答是正確的。這只是解釋爲什麼你不能僅僅背景條件。 – chepner

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個完成之前加註