Как запустить команду в среднем 5 раз в секунду?

У меня есть сценарий командной строки, который выполняет вызов API и обновляет базу данных с результатами.

У меня есть ограничение на 5 вызовов API в секунду с поставщиком API. Для выполнения сценария требуется более 0,2 секунды.

  • Если я буду запускать команду последовательно, она не будет работать достаточно быстро, и я буду делать только 1 или 2 вызова API в секунду.
  • Если я буду запускать команду последовательно, но одновременно с нескольких терминалов, я могу превысить 5 вызовов / второй лимит.

Если есть способ упорядочить потоки, чтобы мой скрипт командной строки выполнялся почти ровно 5 раз в секунду?

Например, что-то, что будет работать с 5 или 10 потоками, и ни один поток не выполнит скрипт, если предыдущий поток выполнил его менее 200 мс назад.

5 Solutions collect form web for “Как запустить команду в среднем 5 раз в секунду?”

В системе 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 с размером по умолчанию размером 64 КБ займет около 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 .

Упрощенно, если ваша команда длится менее 1 секунды, вы можете просто запускать 5 команд каждую секунду. Очевидно, это очень сильно.

 while sleep 1 do for i in {1..5} do mycmd & done done 

Если ваша команда может занять более 1 секунды, и вы хотите разложить команды, которые вы можете попробовать

 while : do for i in {0..4} do sleep .$((i*2)) mycmd & done sleep 1 & wait done 

Кроме того, вы можете иметь 5 отдельных циклов, которые запускаются независимо, с минимальным 1 секундой.

 for i in {1..5} do while : do sleep 1 & mycmd & wait done & sleep .2 done 

С программой C,

Например, вы можете использовать поток, который спит в течение 0,2 секунды

 #include<stdio.h> #include<string.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> pthread_t tid; void* doSomeThing() { While(1){ //execute my command sleep(0.2) } } int main(void) { int i = 0; int err; err = pthread_create(&(tid), NULL, &doSomeThing, NULL); if (err != 0) printf("\ncan't create thread :[%s]", strerror(err)); else printf("\n Thread created successfully\n"); return 0; } В #include<stdio.h> #include<string.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> pthread_t tid; void* doSomeThing() { While(1){ //execute my command sleep(0.2) } } int main(void) { int i = 0; int err; err = pthread_create(&(tid), NULL, &doSomeThing, NULL); if (err != 0) printf("\ncan't create thread :[%s]", strerror(err)); else printf("\n Thread created successfully\n"); return 0; } 

используйте его, чтобы знать, как создать поток: создать поток (это ссылка, которую я использовал для вставки этого кода)

Используя node.js, вы можете запустить один поток, который выполняет скрипт bash каждые 200 миллисекунд, независимо от того, как долго ответ будет возвращаться, потому что ответ приходит через функцию обратного вызова .

 var util = require('util') exec = require('child_process').exec setInterval(function(){ child = exec('fullpath to bash script', function (error, stdout, stderr) { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (error !== null) { console.log('exec error: ' + error); } }); },200); 

Этот javascript запускается каждые 200 миллисекунд, и ответ получен через функцию функции обратного вызова function (error, stdout, stderr) .

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

Я использовал какое-то время на основе pv решения Stéphane Chazelas, но выяснил, что он вышел случайно (и молча) через некоторое время, от нескольких минут до нескольких часов. – Edit: Причина в том, что мой скрипт PHP иногда умирал из-за превышения максимального времени выполнения, выходящего со статусом 255.

Поэтому я решил написать простой инструмент командной строки, который делает именно то, что мне нужно.

Достижение моей первоначальной цели так же просто, как:

 ./parallel.phar 5 20 ./my-command-line-script 

Он запускает почти ровно 5 команд в секунду, если нет уже 20 параллельных процессов, и в этом случае он пропускает следующее выполнение (ы), пока не станет доступным слот.

Этот инструмент не чувствителен к выходу статуса 255.

  • Является ли crontab многопоточным?
  • Анализ поведения многопоточной программы
  • Параллельные задачи и процесс убийства
  • Как вызвать URL-адрес службы из сценария оболочки bash параллельно?
  • Выполнение процесса несколько раз в одно и то же время
  • Что происходит с многопоточным процессом Linux, если он получает сигнал?
  • Ускорение работы zgrep на многоядерном компьютере
  • многопоточная обработка в AM1808 с использованием встроенного Linux
  • Linux - предотвращение сбоя приложения из-за нехватки дискового пространства
  • unpigz (и untar) в определенный каталог
  • Запуск скрипта python 200 000 раз параллельно с использованием bash
  • Могу ли я использовать kernel_thread в ядре, когда его версия превышает 3.10?
  • Interesting Posts

    При запуске сценария оболочки можно передавать конкретные позиционные параметры без необходимости вводить их в порядок?

    Выделение / исключение / расширение в "команде в переменной"

    Как вы блокируете определенный процесс (например, vim) от доступа к установленному диску?

    Разделить строки внутри файлов с столбцами фиксированной ширины

    Потерял контроль над окнами, отправленными на монитор по HDMI, который xrandr не обнаруживает

    Комбинированное количество слов для файлов в каталогах

    ZSH, vcs_info, Mercurial и Trac: странная ветка и ревизия

    Не удалось установить рейд на моем NAS, пытаясь спасти данные, как мне следует продолжить?

    Является ли cygwin вином, но для Linux-приложений?

    Вставка скрипта Sed и добавление в неправильное место только в одном конкретном месте

    Безопасно отключить загрузку fsck в файловой системе ext3 только для чтения?

    Как установить значение по умолчанию для CPU для всех демонов в systemd?

    прокси-аутентификация не удалась, но только для выбранных пакетов

    Магические переменные окружения в gnome-terminal

    Как сделать pwd и. определить текущий путь по-разному?

    Linux и Unix - лучшая ОС в мире.