ich die TPL (TaskFactory.Startnew) glauben funktioniert ähnlich, dass ich ThreadPool.QueueUserWorkItem t in der Warteschlange Arbeit an einem Thread im Thread-Pool.
Pretty much.
Von dem, was ich gelesen habe scheint es async/warten nur "manchmal" erstellt einen neuen Thread.
Eigentlich tut es nie. Wenn Sie Multithreading haben wollen, müssen Sie es selbst implementieren. Es gibt eine neue Task.Run
Methode, die nur Kurzform für Task.Factory.StartNew
ist, und es ist wahrscheinlich die gebräuchlichste Art, eine Aufgabe im Thread-Pool zu starten.
Wenn Sie IO-Completion-Ports haben, kann ich sehen, dass es keinen neuen Thread erstellen muss, aber ansonsten würde ich denken, dass es nötig wäre.
Bingo. So werden Methoden wie Stream.ReadAsync
tatsächlich einen Task
Wrapper um einen IOCP erstellen (wenn der Stream
einen IOCP hat).
Sie können auch einige Nicht-I/O-, Nicht-CPU- "Tasks" erstellen. Ein einfaches Beispiel ist Task.Delay
, das eine Aufgabe zurückgibt, die nach einiger Zeit abgeschlossen ist.
Die kühle Sache über async
/await
ist, dass Sie etwas Arbeit an den Thread-Pool Warteschlange kann (zB Task.Run
), einige der I/O-gebundenen Betrieb (zB Stream.ReadAsync
), und eine andere Operation tun (zB Task.Delay
) ... und sie sind alle Aufgaben! Sie können erwartet oder in Kombinationen wie Task.WhenAll
verwendet werden.
Jede Methode, die Task
zurückgibt, kann await
ed sein - es muss keine async
Methode sein. So Task.Delay
und I/O-gebundene Operationen verwenden einfach TaskCompletionSource
, um eine Aufgabe zu erstellen und zu vervollständigen - das einzige, was im Thread-Pool getan wird, ist die eigentliche Aufgabe abgeschlossen, wenn das Ereignis auftritt (Timeout, E/A-Abschluss, etc).
Ich denke, mein Verständnis von FromCurrentSynchronizationContext war immer auch ein bisschen unscharf. Ich war immer im Wesentlichen der UI-Thread.
Ich schrieb an article auf SynchronizationContext
. Die meiste Zeit, 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 bedient.
- ist ansonsten ein Thread-Pool-Kontext.
Jeder Thread kann gesetzt sein eigenes SynchronizationContext
, so gibt es Ausnahmen von den obigen Regeln.
beachte, dass der Standard Task
Erwartenden den Rest der async
Methode auf die aktuellen SynchronizationContext
plant, wenn es nicht null ist; ansonsten geht es auf die aktuelle TaskScheduler
. Das ist heute nicht so wichtig, aber in naher Zukunft wird es eine wichtige Unterscheidung sein.
Ich schrieb meine eigene async
/await
intro auf meinem Blog, und Stephen Toub kürzlich gepostet eine hervorragende async
/await
FAQ.
Bezüglich "Nebenläufigkeit" vs "Multithreading", siehe this related SO question. Ich würde sagen, async
ermöglicht Parallelität, die Multithread sein kann oder nicht. Es ist einfach await Task.WhenAll
oder await Task.WhenAny
für die gleichzeitige Verarbeitung zu verwenden, und wenn Sie nicht explizit den Thread-Pool verwenden (z. B. Task.Run
oder ConfigureAwait(false)
), können mehrere gleichzeitige Operationen gleichzeitig ausgeführt werden (z. B. mehrere E/A oder andere) Typen wie Delay
) - und es wird kein Thread für sie benötigt. Ich benutze den Begriff "Single-Threaded Concurrency" für diese Art von Szenario, obwohl in einem ASP.NET-Host, können Sie tatsächlich mit "zero-Threaded Concurrency" enden. Das ist ziemlich süß.
Tatsächlich garantiert TaskCreationOptions.LongRunning keinen "neuen Thread". Pro MSDN * bietet die Option "LongRunning" nur einen Hinweis für den Scheduler; es garantiert keinen dedizierten Thread. * Ich fand das auf die harte Tour. – eduncan911
@ eduncan911 obwohl das, was Sie über die Dokumentation sagen, korrekt ist, habe ich den TPL-Quellcode eine Weile zurückgeschaut und ich bin mir ziemlich sicher, dass tatsächlich ein neuer dedizierter Thread immer dann erstellt wird, wenn 'TaskCreationOptions.LongRunning' spezifiziert ist. –
@ZaidMasud: Vielleicht möchten Sie einen anderen Blick werfen.Ich weiß, dass es die Threads zusammenfasste, weil 'Thread.CurrentThread.IsThreadPoolThread' True für kurz laufende Threads von einigen hundert Millisekunden zurückgab. ganz zu schweigen von den ThreadStatic-Variablen, die ich in mehrere Threads blutete, was zu allen Arten von Havok führte. Ich musste meinen Code dazu zwingen, mehrere Threads() s neu zu schreiben, um einen dedizierten Thread zu garantieren. Mit anderen Worten, ich konnte die TaskFactory nicht für dedizierte Threads verwenden. Optional können Sie einen eigenen TaskScheduler implementieren, der immer einen dedizierten Thread zurückgibt. – eduncan911