Wenn Multithreading mit "Thread.new ()" durchgeführt wurde, trat in Heroku ein Ressourcenmangelfehler auf.
can't create Thread: Resource temporarily unavailable (ThreadError)
Ich habe eine Thread-Fehlerbehandlung und einen Wiederholungsmechanismus erstellt, der Threads nach besten Kräften verwendet.
Übrigens ist die Anzahl der von Heroku ausführbaren Prozessthreads recht begrenzt. Achten Sie daher auf den Unterschied zur lokalen Umgebung.
https://devcenter.heroku.com/articles/limits#processes-threads
Stand 2020/08
free, hobby and standard-1x dynos support no more than 256
standard-2x and private-s dynos support no more than 512
performance-m and private-m dynos support no more than 16384
performance-l and private-l dynos support no more than 32768
Wenn Ihre lokale Umgebung MacOS ist, können Sie den Befehl sysctl kern.num_taskthreads
verwenden, um die maximale Anzahl von Threads pro Prozess zu ermitteln.
$ sysctl kern.num_taskthreads
kern.num_taskthreads: 4096
Es besteht eine hohe Wahrscheinlichkeit, dass ein Konstruktionsfehler beim Auslaufen der Gewinde gemacht wird, wenn die Last etwas höher als gewöhnlich ist.
Überlegen Sie zunächst, wie Sie die Anzahl der Threads reduzieren können, die eingerichtet werden müssen, z. B. ob die Verarbeitung an einen anderen Server delegiert werden kann oder ob aufgrund der API-Spezifikationen eine Möglichkeit besteht, mit einer kleinen Anzahl von Anforderungen umzugehen.
def retry_threads(times: 3)
try = 0
begin
try += 1
Thread.new { yield }
rescue ThreadError
sleep(1 * try)
retry if try < times
raise
end
end
Wenn kein Thread verfügbar ist, warten Sie einige Sekunden und versuchen Sie es erneut.
Die Anzahl der Wartesekunden ist variabel, z. B. 1 Sekunde für die erste Wiederholung und 2 Sekunden für die zweite Wiederholung, um Zeitverlust zu vermeiden.
Es gibt auch eine Möglichkeit, Wiederholungsversuche detailliert zu verwalten, indem die Wartezeit auf Mikrosekunden festgelegt wird.
Tatsächliche Nutzung
def heavy_task(url)
#Schwere Verarbeitung
end
# urls = ["...","...",...]
threads = []
urls.all each do |url|
threads << retry_threads{ heavy_task(url) }
end
threads.each(&:join)
Wir haben untersucht, um wie viel die Toleranz für das Einfädeln durch diesen Wiederholungsmechanismus tatsächlich erhöht wurde.
def heavy_task
sleep(10)
end
def retry_threads(times: 3)
try = 0
begin
try += 1
Thread.new { yield }
rescue ThreadError
sleep(1 * try)
retry if try < times
p $count
raise
end
end
def no_retry_threads()
begin
Thread.new { yield }
rescue ThreadError
p $count
raise
end
end
$count = 0
#Kein erneuter Versuch
loop do
no_retry_threads{ heavy_task }
$count += 1
end
#Mit erneutem Versuch
loop do
retry_threads{ heavy_task }
$count += 1
end
Der Wert der Anzahl der Aufgaben, die in der lokalen Umgebung 10 Sekunden gedauert haben (maximale Anzahl der Threads: 4096).
Keine Wiederholungsversuche | Mit erneutem Versuch |
---|---|
4094 | 212888 |
Recommended Posts