Ich habe ein Befehlszeilenskript, das einen API-Aufruf ausführt und eine Datenbank mit den Ergebnissen aktualisiert.
Ich habe ein Limit von 5 API-Aufrufen pro Sekunde beim API-Anbieter. Die Ausführung des Skripts dauert mehr als 0,2 Sekunden.
- Wenn ich den Befehl nacheinander ausführe, läuft er nicht schnell genug und ich rufe nur 1 oder 2 APIs pro Sekunde auf.
- Wenn ich den Befehl nacheinander, aber gleichzeitig von mehreren Terminals aus ausführe, überschreite ich möglicherweise die Grenze von 5 Anrufen / Sekunde.
Gibt es eine Möglichkeit, Threads so zu orchestrieren, dass mein Befehlszeilenskript fast genau fünfmal pro Sekunde ausgeführt wird?
Zum Beispiel würde etwas mit 5 oder 10 Threads ausgeführt, und kein Thread würde das Skript ausführen, wenn ein vorheriger Thread es vor weniger als 200 ms ausgeführt hat.
command-line
multithreading
Benjamin
quelle
quelle
Antworten:
Auf einem GNU-System und wenn Sie haben
pv
, können Sie Folgendes tun:Der
-P20
soll höchstens 20$cmd
gleichzeitig ausführen .-L10
begrenzt die Rate auf 10 Bytes pro Sekunde, also 5 Zeilen pro Sekunde.Wenn Ihr
$cmd
s zwei langsam wird und das Limit von 20 erreicht,xargs
hört das Lesen auf, bis$cmd
mindestens eine Instanz zurückkehrt.pv
schreibt weiterhin mit der gleichen Rate an die Pipe, bis die Pipe voll ist (was unter Linux mit einer Standard-Pipe-Größe von 64 KB fast 2 Stunden dauert).An diesem Punkt
pv
wird aufhören zu schreiben. Aber selbst dann, wennxargs
das Lesen fortgesetzt wird,pv
wird versucht, alle Zeilen, die es früher hätte senden sollen, so schnell wie möglich einzuholen und zu senden, um insgesamt einen Durchschnitt von 5 Zeilen pro Sekunde aufrechtzuerhalten.Das heißt, solange es mit 20 Prozessen möglich ist, diese 5 Durchläufe pro Sekunde im Durchschnitt zu erreichen, wird es dies tun. Wenn das Limit erreicht ist, wird die Rate, mit der neue Prozesse gestartet werden, nicht vom Timer von pv gesteuert, sondern von der Rate, mit der frühere cmd-Instanzen zurückkehren. Wenn zum Beispiel derzeit 20 ausgeführt werden und 10 Sekunden vergangen sind und 10 von ihnen sich dafür entscheiden, alle gleichzeitig zu beenden, werden sofort 10 neue gestartet.
Beispiel:
Im Durchschnitt sind es 5-mal pro Sekunde, auch wenn die Verzögerung zwischen zwei Läufen nicht immer genau 0,2 Sekunden beträgt.
Mit
ksh93
(oder mit,zsh
wenn Ihrsleep
Befehl Sekundenbruchteile unterstützt):Damit ist die Anzahl der gleichzeitigen
your-command
s jedoch nicht begrenzt.quelle
pv
scheint der Befehl genau das zu sein, wonach ich gesucht habe, ich könnte nicht besser hoffen! Nur in dieser Zeile:yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
Ist die letzte nichtsh
überflüssig?sh
ist für das$0
in deinem$cmd
Drehbuch. Es wird auch in Fehlermeldungen von der Shell verwendet. Ohne es$0
wärey
vonyes
, so würden Sie Fehlermeldungen wie erhalteny: cannot execute cmd
... Sie könnten auch tunyes sh | pv -qL15 | xargs -n1 -P20 sh -c "$cmd"
sh
. und in meinen Tests kann ich, wenn ich es entferne, keinen Unterschied feststellen!$cmd
es verwenden$0
(warum sollte es?) Und für Fehlermeldungen. Versuchen Sie es zum Beispiel mitcmd=/
; ohne die zweitesh
, dann würden Sie so etwas wie seheny: 1: y: /: Permission denied
stattsh: 1: sh: /: Permission denied
Wenn Ihr Befehl weniger als 1 Sekunde dauert, können Sie einfach 5 Befehle pro Sekunde starten. Offensichtlich ist das sehr platzen.
Wenn Ihr Befehl länger als 1 Sekunde dauert und Sie die Befehle verteilen möchten, können Sie es versuchen
Alternativ können Sie 5 separate, unabhängig voneinander ablaufende Schleifen mit einem Minimum von 1 Sekunde erstellen.
quelle
Mit einem C-Programm
Sie können beispielsweise einen Thread verwenden, der nach einer Weile 0,2 Sekunden lang ruht
benutze es, um zu wissen, wie man einen Thread erstellt: erstelle einen Thread (dies ist der Link, über den ich diesen Code eingefügt habe)
quelle
cc
ist ein vorhandenes Unix-Tool, und das ist nicht viel Code!Mit node.js können Sie einen einzelnen Thread starten , der das Bash-Skript alle 200 Millisekunden ausführt, unabhängig davon, wie lange die Rückmeldung dauert, da die Rückmeldung über eine Rückruffunktion erfolgt .
Dieses Javascript wird alle 200 Millisekunden ausgeführt und die Antwort wird über die Rückruffunktion abgerufen
function (error, stdout, stderr)
.Auf diese Weise können Sie steuern, dass die 5 Aufrufe pro Sekunde niemals überschritten werden, unabhängig davon, wie langsam oder schnell die Ausführung des Befehls ist oder wie lange auf eine Antwort gewartet werden muss.
quelle
Ich habe
pv
einige Zeit die auf Stéphane Chazelas basierende Lösung verwendet, aber festgestellt, dass sie nach einiger Zeit zufällig (und lautlos) beendet wurde, irgendwo zwischen einigen Minuten und einigen Stunden. - Bearbeiten: Der Grund war, dass mein PHP-Skript gelegentlich aufgrund einer überschrittenen maximalen Ausführungszeit beim Beenden mit dem Status 255 abgestürzt ist.Also habe ich beschlossen, ein einfaches Befehlszeilentool zu schreiben , das genau das tut, was ich brauche.
Mein ursprüngliches Ziel zu erreichen ist so einfach wie:
Es werden fast genau 5 Befehle pro Sekunde gestartet, es sei denn, es gibt bereits 20 gleichzeitige Prozesse. In diesem Fall werden die nächsten Ausführungen übersprungen, bis ein Slot verfügbar wird.
Dieses Tool reagiert nicht auf einen Exit mit Status 255.
quelle