Продолжение задачи не запланировано в потоке пула потоков
Я читал о SynchronizationContext и его использовании с методами async/await ( ссылка). Насколько я понимаю, в консольном приложении, где SynchronizationContext имеет значение null, продолжение ожидаемого метода (Task) будет запланировано с планировщиком по умолчанию, который будет ThreadPool.
Но если я запустите это консольное приложение, вы увидите, что продолжение запущено в созданном мною рабочем потоке:
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);
}
}
И вот вывод:
MainThreadId=10
Method1 => Entered. ThreadId=10
Method1 => Started new thread. ThreadId=11
Method1 => After WorkerThread. ThreadId=11
After Method1. ThreadId=12
Как видите, "After WorkerThread" был выведен в том же потоке, что и мой рабочий поток, но не в пуле потоков.
Я нашел похожий вопрос, но парень использовал Mono, и они говорили, что это ошибка. Со своей стороны, я собрал этот код в Visual Studio и запустил его под Windows 7 и.Net 4.5.2, установленными на моем компьютере.
Может ли кто-нибудь объяснить это поведение?
1 ответ
Это из-за деталей реализации, которые я задокументировал в своем блоге: продолжение, созданное await
планируется с использованием ExecuteSynchronously
флаг. В том случае, когда пришло время запустить продолжение (т. Е. В TaskCompletionSource<T>.SetResult
вызовите рабочий поток), планировщик по умолчанию сначала пытается определить, может ли он работать в текущем потоке.
Так как рабочий поток не имеет TaskScheduler
который отклонит выполнение задачи синхронно, ExecuteSynchronously
флаг заставит планировщик задач пула потоков просто выполнять задачу синхронно (т. е. в вызывающем потоке).