Многопоточные Операторы Bash If

каков правильный способ многопоточного независимого if операторы в сценарии bash? Лучше всего разместить & после кода, содержащегося в 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 будет оцениваться и только как начинается первая задача будет 2nd 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 ответов


если вы хотите, чтобы каждый if условие для выполнения в контексте его соответствующего "потока" (на самом деле процесс subshell), то я думаю, что нужно сделать, это поставить & после закрытия fi заявление для каждого if. Тогда оценка каждого if выражение вместе с условным кодом wiil происходит полностью в контексте собственного "потока".

например:

#/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()). См. многопоточность в Bash. Вы можете проверить это, создав переменную, например n=0 перед запуском" потоков". Затем в одном потоке инкремент n и Эхо $n во всех потоках. Вы увидите, что каждый "поток" получает свою собственную копию n - n будет иметь разные значения в увеличивающихся и не увеличивающихся потоках. fork() создает новую копию процесса (включая независимые копии переменных);pthread_create() нет.


помещения & после if будет только фон оценки условного выражения;[ на самом деле псевдоним , а вот что будет backgrouded, а не задача.

помещения & после задачи будет фон задачи. Степень, в которой задачи расположены в шахматном порядке, а не одновременно, зависит от относительного времени, необходимого для оценки 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 одновременны по мере того как они backgrounded.

последний вариант описано @DigitalTrauma:

#!/bin/bash

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

тогда все if утверждение является backgrounded, т. е. как оценка 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 секунд времени


сравнить

if false
then
  echo "condition true"
fi

С

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

команда расторгнут & немедленно выходит со статусом 0, поэтому if филиала принимается независимо от того, что фоновый процесс в конечном итоге возвращается. Не имеет смысла помещать команду, которая безоговорочно преуспевает в списке команд if заявление. Вы должны позволить ему завершить, чтобы тело могло быть правильно (условно) выполнено.


ответы до сих пор полагаются на использование нереста 3 и ждут завершения всех 3, прежде чем начать снова.

"лучший" способ в bash использует jobs команда типа so

jobs|wc -l а затем цикл с небольшой командой сна, как так

(не проверял код)

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

    expression &
    fi
    sleep 10;

done

Это позволит заполнить все 3 "потока", не дожидаясь завершения всех 3 перед заправкой