У системі GNU, і якщо у вас є pv
, ви можете зробити:
cmd='
that command | to execute &&
as shell code'
yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
-P20
Це виконати не більше 20 $cmd
одночасно.
-L10
обмежує швидкість до 10 байт в секунду, тому 5 рядків в секунду.
Якщо ваш $cmd
s стане двома повільними і спричинить досягнення межі 20, то xargs
перестане читати, доки $cmd
принаймні один екземпляр не повернеться. pv
продовжуватиме писати на трубу з тією ж швидкістю, поки труба не заповниться (що для Linux з розміром труби за замовчуванням 64KiB займе майже 2 години).
У цей момент pv
перестане писати. Але навіть тоді, коли xargs
відновить читання, pv
спробує наздогнати та надіслати всі рядки, які він повинен був надіслати раніше, як можна швидше, щоб підтримувати загальну середню 5 рядків на секунду.
Це означає, що доки за допомогою 20 процесів можна виконати середню вимогу 5 запуску в секунду, вона це зробить. Однак при досягненні межі швидкість, з якою починаються нові процеси, визначається не таймером pv, а швидкістю, з якою повертаються попередні екземпляри cmd. Наприклад, якщо зараз працює 20 і пройшло протягом 10 секунд, і 10 з них вирішили закінчити всі одночасно, то 10 нових буде запущено відразу.
Приклад:
$ cmd='date +%T.%N; exec sleep 2'
$ yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
09:49:23.347013486
09:49:23.527446830
09:49:23.707591664
09:49:23.888182485
09:49:24.068257018
09:49:24.338570865
09:49:24.518963491
09:49:24.699206647
09:49:24.879722328
09:49:25.149988152
09:49:25.330095169
В середньому це буде 5 разів на секунду, навіть якщо затримка між двома пробіжками не завжди буде рівно 0,2 секунди.
З ksh93
(або з, zsh
якщо ваша sleep
команда підтримує дробові секунди):
typeset -F SECONDS=0
n=0; while true; do
your-command &
sleep "$((++n * 0.2 - SECONDS))"
done
Однак це не обмежує кількість одночасних your-command
s.