Ich glaube, dass die TPL (TaskFactory.Startnew) ähnlich wie ThreadPool.QueueUserWorkItem funktioniert, da sie die Arbeit an einem Thread im Thread-Pool in die Warteschlange stellt.
So ziemlich .
Nach dem, was ich gelesen habe, scheint es, als würde async / wait nur "manchmal" einen neuen Thread erstellen.
Eigentlich tut es das nie. Wenn Sie Multithreading möchten, müssen Sie es selbst implementieren. Es gibt eine neue Task.Run
Methode, die nur eine Abkürzung ist Task.Factory.StartNew
, und sie ist wahrscheinlich die häufigste Methode, um eine Aufgabe im Thread-Pool zu starten.
Wenn Sie sich mit E / A-Abschlussports befassen, kann ich sehen, dass kein neuer Thread erstellt werden muss, aber ansonsten würde ich denken, dass dies erforderlich ist.
Bingo. Methoden wie Stream.ReadAsync
erstellen also tatsächlich einen Task
Wrapper um ein IOCP (wenn dasStream
einen IOCP hat).
Sie können auch einige Nicht-E / A- und Nicht-CPU- "Aufgaben" erstellen. Ein einfaches Beispiel ist Task.Delay
, dass eine Aufgabe zurückgegeben wird, die nach einiger Zeit abgeschlossen ist.
Das Coole an async
/ await
ist, dass Sie einige Arbeiten in den Thread-Pool einreihen können (z. B. Task.Run
), eine E / A-gebundene Operation ausführen (z. B. Stream.ReadAsync
) und eine andere Operation ausführen können (z. B. Task.Delay
) ... und sie sind alle Aufgaben! Sie können erwartet oder in Kombinationen wie verwendet werden Task.WhenAll
.
Jede Methode, die zurückgibt, Task
kann await
bearbeitet werden - es muss keine async
Methode sein. So Task.Delay
und I / O-gebundene Operationen verwenden nur TaskCompletionSource
zu erstellen und zu einer Aufgabe - das einzige , was auf dem Thread - Pool durchgeführt wird , ist der eigentliche Aufgabe Abschluss , wenn das Ereignis eintritt (Timeout, I / O - Abschluss, usw.).
Ich denke, mein Verständnis von FromCurrentSynchronizationContext war auch immer ein bisschen verschwommen. Ich habe immer gesagt, dass es im Wesentlichen der UI-Thread war.
Ich habe einen Artikel über geschrieben SynchronizationContext
. Meistens SynchronizationContext.Current
:
- ist ein UI-Kontext, wenn der aktuelle Thread ein UI-Thread ist.
- ist ein ASP.NET-Anforderungskontext, wenn der aktuelle Thread eine ASP.NET-Anforderung bearbeitet.
- ist sonst ein Thread-Pool-Kontext.
Jeder Thread kann seinen eigenen Thread festlegen SynchronizationContext
, daher gibt es Ausnahmen zu den oben genannten Regeln.
Beachten Sie, dass der Standard- Task
Kellner den Rest der async
Methode für die aktuelle Methode plant, SynchronizationContext
wenn sie nicht null ist . sonst geht es auf den Strom TaskScheduler
. Dies ist heute nicht so wichtig, aber in naher Zukunft wird es eine wichtige Unterscheidung sein.
Ich habe mein eigenes async
/ await
Intro in meinem Blog geschrieben und Stephen Toub hat kürzlich eine exzellente async
/ await
FAQ gepostet .
Informationen zu "Parallelität" und "Multithreading" finden Sie in dieser verwandten SO-Frage . Ich würde sagen, async
aktiviert Parallelität, die Multithreading sein kann oder nicht. Es ist einfach zu verwenden await Task.WhenAll
oder await Task.WhenAny
gleichzeitig zu verarbeiten. Wenn Sie den Thread-Pool nicht explizit verwenden (z. B. Task.Run
oder ConfigureAwait(false)
), können mehrere gleichzeitige Vorgänge gleichzeitig ausgeführt werden (z. B. mehrere E / A oder andere Arten wie Delay
). und es wird kein Thread für sie benötigt. Ich verwende den Begriff "Single-Threaded-Parallelität" für diese Art von Szenario, obwohl in einem ASP.NET-Host tatsächlich " Null- Threaded-Parallelität" auftreten kann. Welches ist ziemlich süß.