2014-11-15 4 views
5

Ich las über SynchronizationContext und seine Verwendung mit den Async/await-Methoden (link). Aus meiner Sicht wird in einer Konsolenanwendung, in der SynchronizationContext null ist, die Fortsetzung einer erwarteten Methode (Task) mit dem Standard-Scheduler geplant, bei dem es sich um den ThreadPool handelt.Taskfortsetzung wurde nicht im Thread-Pool-Thread geplant

Aber wenn ich diese Konsole app ausführen, werden Sie von der Ausgabe sehen, dass die die Fortsetzung auf dem Worker-Thread ausgeführt wird, die ich erstellt:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine("MainThreadId=" + Thread.CurrentThread.ManagedThreadId); 
     Method1().ContinueWith(t => 
     { 
      Console.WriteLine("After Method1. ThreadId=" + Thread.CurrentThread.ManagedThreadId); 
     }); 

     Console.ReadKey(); 
    } 

    public static async Task Method1() 
    { 
     Console.WriteLine("Method1 => Entered. ThreadId=" + Thread.CurrentThread.ManagedThreadId); 

     TaskCompletionSource<bool> completionSource = new TaskCompletionSource<bool>(); 
     Thread thread = new Thread(() => 
     { 
      Console.WriteLine("Method1 => Started new thread. ThreadId=" + Thread.CurrentThread.ManagedThreadId); 
      Thread.Sleep(2000); 
      completionSource.SetResult(true); 
     }); 

     thread.Start(); 

     await completionSource.Task; 

     Console.WriteLine("Method1 => After WorkerThread. ThreadId=" + Thread.CurrentThread.ManagedThreadId); 
    } 
} 

Und hier ist die Ausgabe:

MainThreadId=10 
Method1 => Entered. ThreadId=10 
Method1 => Started new thread. ThreadId=11 
Method1 => After WorkerThread. ThreadId=11 
After Method1. ThreadId=12 

Wie Sie sehen können: "Nach WorkerThread" wurde im selben Thread wie mein Arbeitsfaden ausgegeben, aber nicht im Threadpool.

Ich fand eine ähnliche question, aber der Typ war mit Mono und sie sagten, dass dies ein Fehler war. Auf meiner Seite habe ich diesen Code in Visual Studio erstellt und unter Windows 7 und .Net 4.5.2 auf meinem Computer ausgeführt.

Könnte jemand bitte dieses Verhalten erklären?

Antwort

5

Es ist wegen einer implementation detail that I documented on my blog: die Fortsetzung von await erstellt wird mit der ExecuteSynchronously Flag geplant. In diesem Fall, wenn es an der Zeit ist, die Fortsetzung auszulösen (d. H. In dem TaskCompletionSource<T>.SetResult Aufruf des Worker-Threads), versucht der Standard-Scheduler zuerst festzustellen, ob er auf dem aktuellen Thread laufen kann.

Since the worker thread has no TaskScheduler that will reject executing the task synchronously wird das ExecuteSynchronously Flag cause the thread pool task scheduler to just execute the task synchronously (d. H. Auf den aufrufenden Thread).

+0

Guter Fang! Daher ist dieser [Artikel] (http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx?PageIndex=2#comments) falsch, wenn er sagt, dass "wenn die Aufgabe erwartet wird, abgeschlossen ist Eine Fortsetzung führt den Rest der asynchronen Methode aus. Wenn der erfasste SynchronizationContext den Wert null hat, wird RestOfMethod() im ursprünglichen TaskScheduler ausgeführt (häufig TaskScheduler.Default, also ThreadPool) "? – Absolom

+2

@Absolom: Technisch wird es im Thread-Pool-Task-Scheduler ausgeführt. Das seltsame Verhalten ist darauf zurückzuführen, dass der Thread-Pool-Task-Scheduler entscheidet, dass Ihr Thread Teil seines Kontexts ist. –

+0

Danke für die Klarstellung, aber könnten Sie erklären, warum in meinem Beispiel die "After Method1" vom Thread Pool Task Scheduler geplant ist und tatsächlich auf dem Thread-Pool und nicht auf dem gleichen Thread ausgeführt wird. Warum ist das Verhalten von Async und Task nicht gleich? – Absolom

Verwandte Themen