У системі 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 рядків в секунду.
Якщо ваш $cmds стане двома повільними і спричинить досягнення межі 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-commands.