Laden...

Wie kann ich Requests am besten parallel abarbeiten?

Erstellt von Sarevok vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.995 Views
S
Sarevok Themenstarter:in
2 Beiträge seit 2019
vor 5 Jahren
Wie kann ich Requests am besten parallel abarbeiten?

Liebe Gemeinde-

Ich mache grade meine ersten Schritte mit C# und .NET, genauer gesagt ganz simple Konsolenanwendungen in .NET Core und Visual Studio Code.

Ich habe nun eine Anwendung welche aus einer externen Quelle Daten bekommt, diese eine Weile lang aufbereitet und schließlich auf einem Webserver speichert.

Mittlerweile gehe ich noch ganz stumpf seriell vor:1.Daten einholen 1.Daten aufbereiten 1.Daten versenden

Klar: Schritt 1,2 & 3 ließen sich optimieren indem dort parallel gearbeitet würde - Die Möglichkeiten in C# mit System.Threading.Tasks.Parallel sind so enorm wie komfortabel - Das bekomme ich noch hin.

Mir geht es darum dass ich nach dem Einholen (1) der ersten Daten eigentlich schon diese aufbereiten (2) könnte. Und wenn aufbereitet, schon versenden (3). Das, während noch Daten weiter abgeholt werden (1), denn es sind einige.

Meine Frage: Wie macht man das in C# typischerweise? Ich tue mich schwer hier etwas zu finden. Klar könnte man einfach Dinge in eine Warteschlange für jeweils Schritt 1, 2, 3 packen und jeweils ein Thread kümmert sich um die Dinge aus der für ihn gedachten Warteschlage.

Aber ich würde erwarten dass es hier in der Standard-Bibliothek etwas gibt, dieses "Pipelining" wäre ja kein so unübliches Konzept. Kann mir hier jemand aushelfen? Ich fand bislang nur ein komisches DataFlow-Ding, aber das scheint noch nicht einmal Bestandteil der Standard .NET Bibliothek zu sein...

T
2.219 Beiträge seit 2008
vor 5 Jahren

Da die Prozesse am Fließband abgearbeitet werden müssen, kannst du pro Durchlauf für alle drei Abläufe einen Thread verwenden.
Entsprechend macht es Sinn alle drei Abläufe durch einen Task verarbeiten zu lassen.
Somit kannst du pro Durchlauf einen eigenen Task erstellen lassen, der dann eben alle drei Prozesse durchläuft.

Nachtrag:
Da du nicht auf alle Daten in Schritt 1 warten musst , kannst du hier z.B. mit yield return bei 1 dann jeweils den aktuellen Datensatz liefern.
Somit kannst du in einer einfachen foreach Schleife solange Daten lesen und an 2 weiterleiten, bis es keine Daten mehr gibt.
Dann kannst du von 2 das Ergebnis abwarten per async/await um es dann wieder bei 3 an den Webserver zu senden.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

S
Sarevok Themenstarter:in
2 Beiträge seit 2019
vor 5 Jahren

Stimmt, Schritt 1, 2 und 3 folgen ja zwingend aufeinander. Das ist ein guter Punkt.

Auch dieses komische yield-Gedöns hatte ich schon nicht mehr auf dem Schirm, daran muss man sich erst einmal gewöhnen. Vielen Dank für den Tipp 👍

16.807 Beiträge seit 2008
vor 5 Jahren

Da die Prozesse am Fließband abgearbeitet werden müssen, kannst du pro Durchlauf für alle drei Abläufe einen Thread verwenden.
Entsprechend macht es Sinn alle drei Abläufe durch einen Task verarbeiten zu lassen.
Somit kannst du pro Durchlauf einen eigenen Task erstellen lassen, der dann eben alle drei Prozesse durchläuft.

ganz klares, dickes, deutliches Nein; das macht kein Sinn!
Das passt nicht, denn das würde auch nicht skalieren - außer Sarevok will gar keine skalierende Lösung. 😉

Das widerspricht auch dem Sinn von Datenfluss.
Die Idee von Datenfluss ist auch, dass unterschiedliche Aufgaben, die unterschiedliche Ressourcen (IO vs CPU vs RAM) und Zeit benötigen auch unterschiedlich skaliert werden.
Das geht natürlich nicht, wenn alles in einem Ausführungsrahmen (Thread oder Task) erfolgt.

Und genau das hier haben wir hier offensichtlich: I/O und CPU-bound tasks.
Das unter einen Hut zu packen: absolut not best practise!
Seit Jahren betreibt Microsoft große Anstrengungen mit Dokumentation, Bibliotheken und Co, dass die Leute eben nicht mehr alles in einen Task packen!
Siehe auch die Archiv-Dokumentation aus 2012 des DataFlow-Vorgängers: Pipelines Basics inkl. entsprechender Grafiken. ⚠

Daher widerspreche ich auch

Entsprechend macht es Sinn alle drei Abläufe durch einen Task verarbeiten zu lassen.

in vollem Umfang.

Aber DataFlow ist der korrekte Ansatz hier. 👍

Ich fand bislang nur ein komisches
>
-Ding, aber das scheint noch nicht einmal Bestandteil der Standard .NET Bibliothek zu sein...

System.Threading.Tasks.Dataflow

PS: .NET Standard ist keine Bibliothek, sondern als Interface zu sehen. .NET Core bzw. .NET Framework ist dann eine Implementierung dessen.
Der Standard deckt die Funktionalitäten eines gemeinsamen Grundstandards ab, auf dem dann Bibliotheken wie DataFlow basieren bzw. entwickelt werden können.
Es ist aber nicht notwendig oder gedacht, dass Dinge wie DataFlow Teil des Standards sind - macht kein Sinn.
PPS: yield ist kein Skalierungswerkzeug. 😉

6.911 Beiträge seit 2009
vor 5 Jahren

Hallo T-Virus,

Entsprechend macht es Sinn alle drei Abläufe durch einen Task verarbeiten zu lassen.

du hast sicher "je einen Task" gemeint?
Wenn das dann korrekt umgesetzt wird, so sind wir bei Abts Antwort.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

16.807 Beiträge seit 2008
vor 5 Jahren

du hast sicher "je einen Task" gemeint?

Entsprechend

Somit kannst du pro Durchlauf einen eigenen Task erstellen lassen, der dann eben alle drei Prozesse durchläuft.

1 Durchlauf = alle drei Prozesse = einen Task

wird er nicht "je einen Task" gemeint haben, sonst würde der Satzzusammenhang insich nicht stimmen.
Dahingehend basierend meine ausführliche, korrigierende Antwort.

T
2.219 Beiträge seit 2008
vor 5 Jahren

@Abt
Hast du meinen Nachtrag bei deinen Antworten ignoriert?
Dieser sagt ja, dass er nicht alles in einem Thread/Task machen muss sondern jeweils nach und nach diese durch eigene Tasks abarbeiten kann.
Ich hatte beim ersten durchlesen überlesen, dass er eben nicht auf alle Daten aus Schritt 1 warten muss sondern diese quasi Stück für Stück abarbeiten kann.

Mit DataFlows habe ich leider keine Erfahrungen, weshalb ich dies erst einmal außer acht gelassen habe.
Wenn dies der korrekte Ansatz ist, dann sind meine Antworten eh hinfällig.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.807 Beiträge seit 2008
vor 5 Jahren

Dein Nachtrag ändert weder am ersten Teil noch an der Sache was; daher ja auch mein Hinweis, dass yield schön und gut ist, aber das halt trotzdem kein Skalierungswerkzeug ist 😉
Und wie geschrieben: auch vor dem Datenfluss war es noch nie eine gute Idee alles in einen Task zu packen (siehe Link aus 2012).

T
461 Beiträge seit 2013
vor 5 Jahren

Hallo,

ich möchte mich für die Verlinkung DataFlow bedanken, das ist nämlich genau das, was ich auch benötige!

Hab mir das angesehen und es ist wirklich ein tolle Sache! Vereinfacht die Arbeit ungemein!

Danke!

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄