在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
答案 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
语句都是背景的,即对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秒运行时间
答案 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个完成再填充