Ihre Ziele sind:
- Verteilen Sie Ihre Arbeit auf viele Maschinen (verteiltes Rechnen / verteilte Parallelverarbeitung)
- Verteilen Sie die Arbeit auf einem bestimmten Computer auf alle CPUs (Multiprocessing / Threading).
Sellerie kann beides ziemlich einfach für Sie erledigen. Das erste, was Sie verstehen müssen, ist, dass jeder Sellerie-Arbeiter standardmäßig so konfiguriert ist, dass er so viele Aufgaben ausführt, wie auf einem System CPU-Kerne verfügbar sind:
Parallelität ist die Anzahl der Prefork-Worker-Prozesse, die zur gleichzeitigen Verarbeitung Ihrer Aufgaben verwendet werden. Wenn alle diese Aufgaben ausgeführt werden, müssen neue Aufgaben warten, bis eine der Aufgaben abgeschlossen ist, bevor sie verarbeitet werden können.
Die Standard-Parallelitätsnummer ist die Anzahl der CPUs auf diesem Computer (einschließlich der Kerne) . Sie können eine benutzerdefinierte Nummer mit der Option -c angeben. Es gibt keinen empfohlenen Wert, da die optimale Anzahl von einer Reihe von Faktoren abhängt. Wenn Ihre Aufgaben jedoch hauptsächlich an E / A gebunden sind, können Sie versuchen, sie zu erhöhen. Experimente haben gezeigt, dass das Hinzufügen von mehr als der doppelten Anzahl von CPUs selten ist effektiv und wahrscheinlich stattdessen die Leistung verschlechtern.
Dies bedeutet, dass sich jede einzelne Aufgabe nicht um die Verwendung von Multiprocessing / Threading kümmern muss, um mehrere CPUs / Kerne zu verwenden. Stattdessen führt Sellerie gleichzeitig genügend Aufgaben aus, um jede verfügbare CPU zu nutzen.
Wenn dies nicht möglich ist, müssen Sie im nächsten Schritt eine Aufgabe erstellen, die die Verarbeitung einer Teilmenge Ihrer Daten übernimmt list_of_millions_of_ids
. Hier haben Sie mehrere Möglichkeiten: Eine besteht darin, dass jede Aufgabe eine einzelne ID verarbeitet, sodass Sie N Aufgaben ausführen, wobei N == len(list_of_millions_of_ids)
. Dies garantiert, dass die Arbeit gleichmäßig auf alle Ihre Aufgaben verteilt wird, da es niemals einen Fall geben wird, in dem ein Mitarbeiter vorzeitig fertig wird und nur wartet. Wenn es Arbeit braucht, kann es eine ID aus der Warteschlange ziehen. Sie können dies (wie von John Doe erwähnt) mit dem Sellerie tun group
.
task.py:
@app.task
def process_id(item):
id = item
database.objects(newid=id).save()
Und um die Aufgaben auszuführen:
from celery import group
from tasks import process_id
jobs = group(process_id.s(item) for item in list_of_millions_of_ids)
result = jobs.apply_async()
Eine andere Möglichkeit besteht darin, die Liste in kleinere Teile aufzuteilen und die Teile an Ihre Mitarbeiter zu verteilen. Bei diesem Ansatz besteht die Gefahr, dass einige Zyklen verschwendet werden, da möglicherweise einige Mitarbeiter warten, während andere noch arbeiten. In der Selleriedokumentation wird jedoch darauf hingewiesen, dass dieses Anliegen häufig unbegründet ist:
Einige befürchten möglicherweise, dass das Aufteilen Ihrer Aufgaben zu einer Verschlechterung der Parallelität führt. Dies gilt jedoch selten für einen ausgelasteten Cluster. In der Praxis kann dies die Leistung erheblich steigern, da Sie den Aufwand für Messaging vermeiden.
Möglicherweise stellen Sie fest, dass das Aufteilen der Liste und das Verteilen der Teile auf die einzelnen Aufgaben aufgrund des geringeren Messaging-Overheads eine bessere Leistung erbringt. Auf diese Weise können Sie wahrscheinlich auch die Datenbank etwas entlasten, indem Sie jede ID berechnen, in einer Liste speichern und dann die gesamte Liste zur Datenbank hinzufügen, sobald Sie fertig sind, anstatt jeweils eine ID zu erstellen . Der Chunking-Ansatz würde ungefähr so aussehen
task.py:
@app.task
def process_ids(items):
for item in items:
id = item
database.objects(newid=id).save()
Und um die Aufgaben zu starten:
from tasks import process_ids
jobs = process_ids.chunks(list_of_millions_of_ids, 30)
jobs.apply_async()
Sie können ein wenig experimentieren, mit welcher Chunking-Größe Sie das beste Ergebnis erzielen. Sie möchten einen Sweet Spot finden, an dem Sie den Messaging-Aufwand reduzieren und gleichzeitig die Größe so klein halten, dass die Mitarbeiter ihren Block nicht viel schneller als ein anderer Mitarbeiter fertigstellen und dann einfach warten, ohne etwas zu tun.