несколько фоновых процессов в скрипте

Предположим, если у меня есть ситуация, когда некоторые файлы нужно скопировать, и это занимает много времени, поэтому мне придется идти на параллельную обработку копии файла. например, это может выглядеть так

for i in ipaddresslist do cp xy & //running in back ground or some other process in background done wait //will cause till all the files are copied or whatever process if all are finished 

теперь я использовал wait чтобы все процессы backgroud были завершены, но в нем есть случаи, подобные

1) некоторая копия файла может произойти раньше, поэтому, если мне нужно выполнить некоторую обработку этих файлов, мне нужно подождать, пока все файлы будут скопированы.

2) если процесс копирования (или любая другая программа, работающая в фоновом режиме) записывает в файл журнала, файл журнала может быть искажен при каждом фоновом процессе, который пытается записать в файл одновременно.

есть ли какое-либо обходное решение для таких вещей: 1) я имею в виду, если я могу знать, что этот процесс завершен, тогда я мог бы начать выполнять оставшуюся обработку для этого конкретного экземпляра процесса (например, копию файла), если он завершен. кроме того, запись в файлы журнала может быть упорядоченной.

внесите предложения

2 Solutions collect form web for “несколько фоновых процессов в скрипте”

Если некоторую работу нужно запустить после копирования какого-либо файла, просто сделайте ее частью фонового задания:

 (cp this /there && start job that needs this in /there) & (cp that /here && start job that needs that in /here) & wait 

(последний & не нужен).

Теперь для более сложных зависимостей вы можете использовать GNU make -j .

 make -j2 -f /dev/fd/3 3<< 'EOF' all: j1 j2 j3 .PHONY: cp1 cp2 cp3 j1 j2 j3 all cp1: cp this /there cp2: cp that /here cp3: cp this /here j1: cp1 start job that needs this in /there j2: cp2 start job that needs that in /here j3: cp1 cp3 start job that needs this in /here and /there EOF 

-j2 будет запускать до двух заданий в любой момент времени, и зависимости будут соблюдаться.

Теперь, чтобы избежать искажения файлов журнала, у вас есть два основных варианта

  1. не чередуйте их, то есть добавляйте содержимое каждого задания один за другим.
  2. попробуйте обеспечить их перемежение красиво, возможно, помечая каждую строку каждой работы, чтобы было легче увидеть, к какой задаче относится эта строка.

Для 1 проще всего сохранить каждый вывод задания в отдельном файле и затем объединить их:

 (cp this /there && start job that needs this in /there) > j1.log 2>&1 & (cp that /here && start job that needs that in /here) > j2.log 2>&1 & wait cat j1.log j2.log > jobs.log 

Другим вариантом является использование каналов для сбора результатов каждого задания и их слияния. Подстановка Shell-процесса, доступная в ksh , zsh или bash может помочь нам в этом и даже позаботиться о фоновой схеме:

 j1() { cp this /there && start job that needs this in /there; } j2() { cp that /here && start job that needs that in /here; } cat <(j1 2>&1) <(j2 2>&1) > jobs.log 

j1 , j2 и cat будут запускаться одновременно и связаны с трубами.

Однако обратите внимание, что cat только начнет считывать со второго канала (который записывается на j2 ) после завершения j1 . Это означает, что если j2 записывает больше протоколов, чем размер канала (например, в Linux, как правило, 64kiB) j2 будет заблокирован до завершения j1 .

Этого можно избежать, используя sponge из moreutils , например:

 cat <(j1 2>&1) <(j2 2>&1 | sponge) > jobs.log 

Хотя это означало бы, что все выходные данные j2 будут храниться в памяти, а cat только начнет записывать вывод j2 в jobs.log после завершения j2 , и в этом случае предпочтительнее использовать pv -qB 100M :

 cat <(j1 2>&1) <(j2 2>&1 | pv -qB 100M) > jobs.log 

Таким образом, j2 будет только приостанавливаться (если j1 еще не закончил) после вывода 100M (плюс два содержимого канала) журналов, и pv не дождался завершения j2 до вывода на stdout.

Обратите внимание, что для всего вышеизложенного вам нужно быть осторожным, если после перенаправления вывода большинства команд на файл или канал (ничего, кроме tty), это повлияет на поведение. Команды, или, скорее, API-интерфейс stdio libc они вызывают ( printf , fputs , fwrite …), обнаруживают, что вывод не идет на терминал и выполняет оптимизацию путем вывода в больших кусках (несколько килобайт), тогда как они не делают этого для стандартной ошибки. Это означает, что на него повлияет порядок вывода и сообщений об ошибках. Если это проблема, для систем GNU или FreeBSD (по крайней мере) и для динамически связанных команд вы можете использовать команду stdbuf :

 stdbuf -oL j1 > j1.log 2>&1 

вместо:

 j1 > j1.log 2>&1 

чтобы выход stdio был буферизирован (каждая строка вывода будет записана отдельно, как только они будут завершены).

Для варианта 2 запись в канал с байтами меньше, чем PIPE_BUF который на Linux составляет 4096 байт, намного превышающий среднюю строку журнала, гарантированно будет атомарным, то есть если два процесса одновременно записываются в один и тот же канал, их 2 записи гарантированно не будут переплетены. Таких гарантий нет в обычных файлах, но я серьезно сомневаюсь, что 2 записи менее 4kiB могут переплетаться с любой ОС или файловой системой.

Так что если бы не эта буферизация, описанная выше, и если строки журнала были выданы отдельно в целом и отдельно, у вас была бы гарантия того, что строки вывода не будут иметь часть строки этого задания, а часть линии этой другой работы.

Однако ничто не мешает команде делать флеш между двумя частями написанной строки (например, printf("foo"); fflush(stdout); printf("bar\n"); ) и нет буферизации на stderr.

Другая проблема заключается в том, что после того, как строки всех заданий будут чередоваться, трудно будет определить, какая строка для этой работы.

Вы можете решить обе проблемы, выполнив что-то вроде:

 tag() { stdbuf -oL sed "s%^%$1: %"; } { j1 2>&1 | tag j1 & j2 2>&1 | tag j2 } | cat > jobs.log 

(обратите внимание, что нам не нужно wait (и это не сработает в большинстве оболочек), потому что cat не закончит, пока больше не будет писать на трубе, так что только до тех пор, пока не будут завершены j1 и j2 ).

Выше мы используем | cat чтобы иметь трубку с гарантией атомарности. Мы передаем вывод каждой команды команде, которая маркирует каждую строку с именем задания. j1 и j2 могут писать свой вывод, но они хотят, sed (из-за stdbuf -oL ) будет выводить строки (с префиксом тега) в целом и отдельно, что гарантирует, что результат не будет искажен.

То же самое замечание, что и выше, все еще применяется: мы не применяем stdbuf -oL к командам в j1 и j2 поэтому они, скорее всего, будут буферизовать их вывод, который может быть написан долго после его создания. Это даже хуже, чем в предыдущем случае, потому что если вы видите:

 j1: doing A j1: doing B j2: doing C 

Это означает, что j1 сделал A перед тем, как делать B, но не то, что он сделал любой из них до того, как j2 выполнил C. Поэтому еще раз вам может понадобиться применить stdbuf -oL к большему количеству команд, если это проблема.

Обратите внимание, что вы не можете применять stdbuf к функциям оболочки, например j1 или j2 выше, но, по крайней мере, с помощью GNU и FreeBSD stdbuf, вы можете использовать это для установки stdbuf во всем мире или на основе stdbuf :

 stdbuf_LD_PRELOAD=$(stdbuf sh -c 'export -p LD_PRELOAD') line_buffered_output() { eval "$stdbuf_LD_PRELOAD" export _STDBUF_O=L } j1() (line_buffered_output; cp this /there && start...) 

Если каждый загруженный файл нуждается в обработке, выполните следующие действия:

 cp whatever file; process file & 

вместо.

Если вы обеспокоены тем, что файлы журналов искажены, возможно, вам следует использовать syslog(3) , возможно, через logger(1) . Рассмотрите возможность использования nohup(1) если кто-то может выйти из системы (и убить фоновые запущенные процессы indavertently).

  • Разбить заголовок в файле и на основе заголовка заменить значение в файле
  • Как прекратить поиск «родительского» скрипта?
  • Сценарий оболочки не запускается при запуске
  • Как проверить, существует ли приложение в $ PATH?
  • Сценарий, вызываемый .bashrc с «exit», предотвращает вход в систему
  • Есть ли способ слушать процесс?
  • Обновление переменной среды в сценарии оболочки
  • Создание следующего доступного имени файла для шаблона (02-output.log и т. Д.)
  • Установка расширения в php
  • Почему команда history ничего не делает в файле сценария?
  • Замените все вхождения символа в переменной с помощью скрипта korn
  • Interesting Posts
    Linux и Unix - лучшая ОС в мире.