In einem meiner Projekte, das irgendwie ein Aggregator ist, analysiere ich Feeds, Podcasts und so weiter aus dem Internet.
Wenn ich bei einer großen Anzahl von Ressourcen einen sequentiellen Ansatz verwende, dauert es ziemlich lange, alle zu verarbeiten (aufgrund von Netzwerkproblemen und ähnlichen Problemen).
foreach(feed in feeds)
{
read_from_web(feed)
parse(feed)
}
Daher möchte ich Parallelität implementieren und konnte mich nicht entscheiden, ob ich ThreadPools grundsätzlich für die Verarbeitung mit Arbeitsthreads verwenden oder mich einfach auf TPL verlassen soll, um sie zu sortieren.
ThreadPools erledigt den Job mit Sicherheit mit Worker-Threads und ich bekomme das, was ich erwarte (und in Multi-Core-CPU-Umgebungen werden auch die anderen Kerne verwendet).
Aber ich möchte immer noch auch TPL als empfohlene Methode in Betracht ziehen, aber ich bin ein bisschen besorgt darüber. Zunächst weiß ich, dass TPL ThreadPools verwendet, aber zusätzliche Entscheidungsebenen hinzufügt. Ich bin hauptsächlich besorgt über den Zustand, in dem eine Single-Core-Umgebung vorhanden ist. Wenn ich mich nicht irre, beginnt TPL mit einer Anzahl von Worker-Threads, die der Anzahl der verfügbaren CPU-Kerne am Anfang entspricht. Ich befürchte, dass TPL für meinen IO-gebundenen Fall ähnliche Ergebnisse wie der sequentielle Ansatz liefert.
Ist es für IO-gebundene Vorgänge (in meinem Fall das Lesen von Ressourcen aus dem Web) am besten, ThreadPools zu verwenden und die Dinge zu steuern, oder sich besser nur auf TPL zu verlassen? Kann TPL auch in IO-gebundenen Szenarien verwendet werden?
Update : Mein Hauptanliegen ist, dass sich TPL in einer Single-Core-CPU- Umgebung nur wie ein sequentieller Ansatz verhält oder weiterhin Parallelität bietet. Ich lese bereits Parallel Programming mit Microsoft .NET und damit das Buch , konnte aber keine genaue Antwort darauf finden.
Hinweis: Dies ist eine Umformulierung meiner vorherigen Frage [ Ist es möglich, Thread-Parallelität und Parallelität zusammen zu verwenden? ] was ziemlich falsch formuliert war.
Wenn Sie versuchen, den Durchsatz für E / A-gebundene Aufgaben zu maximieren, müssen Sie unbedingt die traditionellen APM-APIs (Asynchronous Processing Model) mit Ihrer TPL-basierten Arbeit kombinieren. Die APM-APIs sind die einzige Möglichkeit, den CPU-Thread zu entsperren, während der asynchrone E / A-Rückruf ansteht. Die TPL bietet die
TaskFactory::FromAsync
Hilfsmethode zur Unterstützung der Kombination von APM- und TPL-Code.In diesem Abschnitt des .NET SDK auf MSDN mit dem Titel TPL und traditionelle asynchrone .NET-Programmierung finden Sie weitere Informationen zum Kombinieren dieser beiden Programmiermodelle, um ein asynchrones Nirvana zu erzielen.
quelle
Sie haben Recht, dass die TPL einen Teil des Steuerelements entfernt, das Sie beim Erstellen Ihres eigenen Thread-Pools haben. Dies ist jedoch nur dann richtig, wenn Sie nicht tiefer graben möchten. Mit der TPL können Sie Aufgaben mit langer Laufzeit erstellen, die nicht Teil des TPL-Thread-Pools sind und Ihren Zweck erfüllen können. Das veröffentlichte Buch, das eine kostenlose gelesene parallele Programmierung mit Microsoft .NET ist, gibt Ihnen viel mehr Einblick, wie die TPL verwendet werden soll. Sie haben immer die Möglichkeit, Paralle.For, Tasks explizite Parameter anzugeben, wie viele Threads zugewiesen werden sollen. Außerdem können Sie den TPL-Scheduler durch Ihren eigenen ersetzen, wenn Sie die volle Kontrolle haben möchten.
quelle
Sie können einer TPL-Aufgabe Ihren eigenen Aufgabenplaner zuweisen . Die Standardarbeit , die man stiehlt , ist allerdings ziemlich klug.
quelle
TaskCreationOptions.LongRunning
könnte sein, was Sie wollen. Ein benutzerdefinierter Planer ist eine weitere Option, wenn Sie den Standardplaner nicht davon überzeugen können, das zu tun, was Sie möchten.Ich denke, es wird. Was ist der Engpass? Wird analysiert oder heruntergeladen? Multithreading hilft Ihnen beim Herunterladen aus dem Internet nicht viel.
Ich würde Task Parallel Library zum Zuschneiden, Anwenden von Masken oder Effekten für heruntergeladene Bilder, Ausschneiden von Beispielen aus Podcasts usw. verwenden. Es ist skalierbarer.
Aber es wird nicht die Größenordnung beschleunigen. Verwenden Sie Ihre Ressourcen, um einige Funktionen zu implementieren und zu testen.
PS. "Wow, meine Funktion wird in 0,7 s statt in 0,9 ausgeführt";)
quelle
Wenn Sie Ihre Anrufe mit den URLs parallelisieren, wird dies Ihrer Meinung nach Ihre Anwendung verbessern, selbst wenn Sie nur einen Kern haben. Schauen Sie sich diesen Code an:
var client = new HttpClient(); var urls = new[]{"a", "url", "to", "find"}; // due to the EAP pattern, this will run in parallel. var tasks = urls.Select(c=> client.GetAsync(c)); var result = Tasks.WhenAll(task).ContinueWith(a=> AnalyzeThisWords(a.Result)); result.Wait(); // don't know if this is needed or it's correct to call wait
Der Unterschied zwischen Multithreading und Asynchronität besteht in diesem Fall darin, wie der Rückruf / die Fertigstellung erfolgt.
Bei Verwendung von EAP hängt die Anzahl der Aufgaben nicht mit der Anzahl der Threads zusammen.
Da Sie sich auf die GetAsync-Aufgabe verlassen, verwendet der http-Client einen Netzwerkstrom (Socket, TCP-Client oder was auch immer) und signalisiert ihm, ein Ereignis auszulösen, wenn BeginRead / EndRead abgeschlossen ist. In diesem Moment sind also keine Threads beteiligt.
Nach dem Aufruf der Fertigstellung wird möglicherweise ein neuer Thread erstellt, aber es liegt an TaskScheduler (verwendet im Aufruf GetAsync / ContinueWith), einen neuen Thread zu erstellen, einen vorhandenen Thread zu verwenden oder die Aufgabe inline zu verwenden, um den aufrufenden Thread zu verwenden.
Wenn die
AnalyzeThisWords
Blöcke zu lange dauern, treten Engpässe auf, da der "Rückruf" auf ContinueWith von einem Thread-Pool-Worker ausgeführt wird.quelle