Der Versuch, den Unterschied zwischen der TPL & zu verstehen async
/ oder await
der Thread-Erstellung .
Ich glaube die TPL (TaskFactory.StartNew
) ähnlich funktioniert, ThreadPool.QueueUserWorkItem
da es die Arbeit an einem Thread im Thread-Pool in die Warteschlange stellt. Das ist natürlich so, es sei denn, Sie verwenden TaskCreationOptions.LongRunning
einen neuen Thread.
ich dachte async
/ await
würde so wesentlich funktionieren:
TPL:
Factory.StartNew( () => DoSomeAsyncWork() )
.ContinueWith(
(antecedent) => {
DoSomeWorkAfter();
},TaskScheduler.FromCurrentSynchronizationContext());
Async
/.Await
:
await DoSomeAsyncWork();
DoSomeWorkAfter();
wäre identisch. Nach dem, was ich gelesen habe, scheint es, dass async
/ await
nur "manchmal" ein neuer Thread erstellt wird. Wann wird ein neuer Thread erstellt und wann wird kein neuer Thread erstellt? 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. Ich denke, mein Verständnis von FromCurrentSynchronizationContext
immer war auch ein bisschen verschwommen. Ich habe immer gesagt, dass es im Wesentlichen der UI-Thread war.
quelle
TaskCreationOptions.LongRunning
angegeben wird.Thread.CurrentThread.IsThreadPoolThread
sie für kurz laufende Threads von einigen hundert Millisekunden wahr waren. Ganz zu schweigen von den ThreadStatic-Variablen, die ich verwendet habe, um in mehrere Threads zu bluten, was zu allerlei Chaos führte. Ich musste meinen Code zwingen, mehrere Threads neu zu erstellen, wie es in der alten Schule üblich war, um einen dedizierten Thread zu gewährleisten. Mit anderen Worten, ich konnte die TaskFactory nicht für dedizierte Threads verwenden. Optional können Sie einen eigenen implementierenTaskScheduler
, der immer einen dedizierten Thread zurückgibt.Antworten:
So ziemlich .
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 istTask.Factory.StartNew
, und sie ist wahrscheinlich die häufigste Methode, um eine Aufgabe im Thread-Pool zu starten.Bingo. Methoden wie
Stream.ReadAsync
erstellen also tatsächlich einenTask
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 werdenTask.WhenAll
.Jede Methode, die zurückgibt,
Task
kannawait
bearbeitet werden - es muss keineasync
Methode sein. SoTask.Delay
und I / O-gebundene Operationen verwenden nurTaskCompletionSource
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 habe einen Artikel über geschrieben
SynchronizationContext
. MeistensSynchronizationContext.Current
: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 derasync
Methode für die aktuelle Methode plant,SynchronizationContext
wenn sie nicht null ist . sonst geht es auf den StromTaskScheduler
. 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 exzellenteasync
/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 verwendenawait Task.WhenAll
oderawait Task.WhenAny
gleichzeitig zu verarbeiten. Wenn Sie den Thread-Pool nicht explizit verwenden (z. B.Task.Run
oderConfigureAwait(false)
), können mehrere gleichzeitige Vorgänge gleichzeitig ausgeführt werden (z. B. mehrere E / A oder andere Arten wieDelay
). 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üß.quelle
async / await vereinfacht grundsätzlich die
ContinueWith
Methoden (Continuations in Continuation Passing Style )Es wird keine Parallelität eingeführt - Sie müssen dies immer noch selbst tun (oder die Async-Version einer Framework-Methode verwenden.)
Die C # 5-Version wäre also:
quelle
DoSomeWorkAsync()
Wartebeispiel wird nicht kompiliert, wenn Rückgaben ungültig sind oder etwas, das nicht erwartet werden kann. In Ihrem ersten Beispiel habe ich angenommen, dass es sich um eine sequentielle Methode handelt, die Sie auf einem anderen Thread ausführen möchten. Wenn Sie es so ändern, dass es a zurückgibtTask
, ohne Parallelität einzuführen, wird es blockiert. In dem Sinne, dass es sequentiell ausgeführt wird und genau wie normaler Code im UI-Thread ist.await
ergibt nur, wenn die Methode eine Wartezeit zurückgibt, die noch nicht abgeschlossen ist.