2014-11-15 18 views
5

Stavo leggendo su SynchronizationContext e il suo utilizzo con i metodi async/await (link). Da quanto ho capito, in un'applicazione Console in cui SynchronizationContext è nullo, la continuazione di un metodo atteso (Task) verrà pianificata con lo scheduler predefinito che sarebbe il ThreadPool.La continuazione dell'attività non era pianificata sul thread del pool di thread

Ma se corro questo console app, vedrete dall'output che la continuazione viene eseguito sul thread di lavoro che ho creato:

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); 
    } 
} 

Ed ecco l'output:

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

Come si può vedere, "Dopo WorkerThread" è stato emesso sullo stesso thread del mio workerthread, ma non sul threadpool.

Ho trovato un simile question ma il ragazzo stava usando Mono e stavano dicendo che questo era un bug. Da parte mia, ho creato questo codice con Visual Studio e l'ho eseguito su Windows 7 e .Net 4.5.2 installato sulla mia macchina.

Qualcuno potrebbe spiegare questo comportamento?

risposta

5

È a causa di un implementation detail that I documented on my blog: la continuazione creata da await è pianificata utilizzando il flag ExecuteSynchronously. In tal caso, quando è il momento di attivare la continuazione (ad esempio, nella chiamata TaskCompletionSource<T>.SetResult sul thread di lavoro), lo scheduler predefinito tenta innanzitutto di determinare se può essere eseguito sul thread corrente.

Since the worker thread has no TaskScheduler that will reject executing the task synchronously, il flag ExecuteSynchronously sarà cause the thread pool task scheduler to just execute the task synchronously (vale a dire sul thread chiamante).

+0

Buona cattura! Quindi questo [articolo] (http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx?PageIndex=2#comments) è errato dicendo che "Quando l'attività attesa è completa , una continuazione eseguirà il resto del metodo asincrono.Se il SynchronizationContext catturato era nullo, allora RestOfMethod() verrà eseguito nel TaskScheduler originale (che è spesso TaskScheduler.Default, che significa ThreadPool) "? – Absolom

+2

@Absolom: Tecnicamente, viene eseguito nell'utilità di pianificazione del pool di thread. Il comportamento anomalo è dovuto al programmatore di attività del pool di thread che decide che il thread è parte del suo contesto. –

+0

Grazie per il chiarimento, ma potresti spiegare perché nel mio esempio il "After Method1" è pianificato dall'utilità di pianificazione del pool di thread ed è in realtà eseguito nel pool di thread e non nello stesso thread. Perché non è lo stesso comportamento per Async e Task? – Absolom