Tengo un script de línea de comandos que realiza una llamada a la API y actualiza una base de datos con los resultados.
Tengo un límite de 5 llamadas API por segundo con el proveedor de API. El script tarda más de 0.2 segundos en ejecutarse.
- Si ejecuto el comando secuencialmente, no se ejecutará lo suficientemente rápido y solo haré 1 o 2 llamadas API por segundo.
- Si ejecuto el comando secuencialmente, pero simultáneamente desde varias terminales, podría exceder el límite de 5 llamadas / segundo.
Si hay una manera de orquestar hilos para que mi script de línea de comandos se ejecute casi exactamente 5 veces por segundo?
Por ejemplo, algo que se ejecutaría con 5 o 10 subprocesos, y ningún subproceso ejecutaría el script si un subproceso anterior lo ejecutó hace menos de 200 ms.
command-line
multithreading
Benjamín
fuente
fuente
Respuestas:
En un sistema GNU y si lo tiene
pv
, podría hacer:El
-P20
es ejecutar como máximo 20$cmd
al mismo tiempo.-L10
limita la velocidad a 10 bytes por segundo, por lo que 5 líneas por segundo.Si sus
$cmd
s se vuelven dos lentos y hace que se alcance el límite de 20,xargs
dejará de leer hasta que$cmd
al menos una instancia regrese.pv
seguirá escribiendo en la tubería a la misma velocidad, hasta que la tubería se llene (lo que en Linux con un tamaño de tubería predeterminado de 64 KB tomará casi 2 horas).En ese punto,
pv
dejará de escribir. Pero incluso entonces, cuandoxargs
reanude la lectura,pv
intentará ponerse al día y enviar todas las líneas que debería haber enviado antes lo antes posible para mantener un promedio general de 5 líneas por segundo.Lo que eso significa es que, siempre que sea posible con 20 procesos para cumplir con ese requisito promedio de 5 ejecuciones por segundo, lo hará. Sin embargo, cuando se alcanza el límite, la velocidad a la que se inician los nuevos procesos no será controlada por el temporizador de pv, sino por la velocidad a la que regresan las instancias de cmd anteriores. Por ejemplo, si 20 se están ejecutando actualmente y lo han estado durante 10 segundos, y 10 de ellos deciden terminar todo al mismo tiempo, se iniciarán 10 nuevos a la vez.
Ejemplo:
En promedio, será 5 veces por segundo, incluso si el retraso entre dos ejecuciones no siempre será exactamente 0.2 segundos.
Con
ksh93
(o conzsh
si susleep
comando admite segundos fraccionarios):Sin
your-command
embargo, eso no limita el número de correos electrónicos concurrentes .fuente
pv
comando parece ser exactamente lo que estaba buscando, ¡no podría esperar mejor! Solo en esta línea:yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
¿no es el últimosh
redundante?sh
es para el$0
en su$cmd
script. También es utilizado en mensajes de error por el shell. Sin él,$0
seríay
deyes
, por lo que obtendría mensajes de error comoy: cannot execute cmd
... También podría hacerloyes sh | pv -qL15 | xargs -n1 -P20 sh -c "$cmd"
sh
; y en mis pruebas, cuando lo elimino, ¡no veo diferencia!$cmd
usa$0
(¿por qué lo haría?) Y para mensajes de error. Prueba por ejemplo concmd=/
; sin el segundosh
,y: 1: y: /: Permission denied
sh: 1: sh: /: Permission denied
Simplísticamente, si su comando dura menos de 1 segundo, puede iniciar 5 comandos por segundo. Obviamente, esto es muy explosivo.
Si su comando puede tomar más de 1 segundo y desea extender los comandos, puede probar
Alternativamente, puede tener 5 bucles separados que se ejecutan independientemente, con un mínimo de 1 segundo.
fuente
Con un programa en C,
Por ejemplo, puede usar un hilo que duerme durante 0.2 segundos en un momento
úselo para saber cómo crear un hilo: cree un hilo (este es el enlace que he usado para pegar este código)
fuente
cc
es una herramienta existente de Unix, ¡y esto no es mucho código!Usando node.js puede iniciar un solo subproceso que ejecuta el script bash cada 200 milisegundos, sin importar cuánto tiempo demore la respuesta en regresar porque la respuesta se realiza a través de una función de devolución de llamada .
Este javascript se ejecuta cada 200 milisegundos y la respuesta se obtiene a través de la función de devolución de llamada
function (error, stdout, stderr)
.De esta manera, puede controlar que nunca supere las 5 llamadas por segundo, independientemente de cuán lenta o rápida sea la ejecución del comando o cuánto tenga que esperar una respuesta.
fuente
He usado la
pv
solución basada en Stéphane Chazelas durante algún tiempo, pero descubrí que salió al azar (y en silencio) después de algún tiempo, desde unos pocos minutos hasta unas pocas horas. - Editar: La razón fue que mi script PHP ocasionalmente murió debido a un tiempo de ejecución máximo excedido, saliendo con el estado 255.Así que decidí escribir una herramienta simple de línea de comandos que haga exactamente lo que necesito.
Lograr mi objetivo original es tan simple como:
Inicia casi exactamente 5 comandos por segundo, a menos que ya haya 20 procesos concurrentes, en cuyo caso omite las siguientes ejecuciones hasta que haya un espacio disponible.
Esta herramienta no es sensible a una salida de estado 255.
fuente