Der Aufruf von _thread.Join()
bewirkt, dass die GetConsumingEnumerable
-Schleife beim letzten Element hängen bleibt. Warum tritt dieses Verhalten auf?
Der Kontext für diesen Ansatz besteht darin, dass ich sicherstellen muss, dass alle Operationen auf einem Betriebssystem-Thread ausgeführt werden, wodurch ein Teil der Anwendung andere Anmeldeinformationen als der Haupt-Thread verwenden könnte.
async-await
arbeitet mit Fortsetzungen. Um effizient zu sein und die Planung zu reduzieren, werden diese Fortsetzungen normalerweise auf demselben Thread ausgeführt, der die vorherige Aufgabe abgeschlossen hat.
Das bedeutet in Ihrem Fall, dass Ihr spezieller Thread nicht nur die Aufgaben ausführt, sondern auch alle Fortsetzungen nach diesen Aufgaben ausführt (die for
Schleife selbst). Sie können dies durch Drucken der Thread-ID sehen:
Wenn die for
-Schleife abgeschlossen ist und die SampleActor
entfernt wurde, rufen Sie Thread.Join
von demselben Thread auf, mit dem Sie sich verbinden möchten, damit Sie einen Deadlock erhalten. Ihre Situation läuft darauf hinaus:
In .Net 4.6 können Sie dies mit TaskCreationOptions.RunContinuationsAsynchronously
lösen, aber in der aktuellen Version können Sie den Standard TaskScheduler
:
Es könnte verlockend sein, eine einfache Überprüfung vorzunehmen, um zu sehen, ob der Thread, den Sie versuchen, Join
ist Thread.CurrentThread
, aber das wäre falsch.
Außerdem denke ich, dass der gesamte Ansatz - das Planen und Ausführen von Cold Task
-Objekten mit einem benutzerdefinierten, nicht TPL-konformen Scheduler - falsch ist . Sie sollten einen TPL-freundlichen Taskplaner verwenden, ähnlich wie Stephen Toub StaTaskScheduler
. Oder führe einen benutzerdefinierten SynchronizationContext
für deinen Aktor-Serving-Thread aus (wie Toubs AsyncPump
) und verwenden Sie TaskScheduler.FromCurrentSynchronizationContext
und Task.Factory.StartNew
, um Aufgaben mit Ihrem benutzerdefinierten Scheduler zu planen (oder verwenden Sie Task.Start(TaskScheduler)
, wenn Sie mit kalten Aufgaben fertig werden müssen).
Auf diese Weise haben Sie die vollständige Kontrolle darüber, wo Aufgaben und deren Fortsetzungen ausgeführt werden, sowie inlining .
Tags und Links c# multithreading task-parallel-library async-await threadpool