Подтвердить что ты не робот

Я думал, что ждут продолжения в той же теме, что и вызывающий, но, похоже, это не так

Я думал, что один из вопросов об async/await заключается в том, что когда задача завершается, продолжение выполняется в том же контексте, когда был вызван ожидание, что в моем случае было бы потоком пользовательского интерфейса.

Итак, например:

Debug.WriteLine("2: Thread ID: " + Thread.CurrentThread.ManagedThreadId);
await fs.ReadAsync(data, 0, (int)fs.Length);
Debug.WriteLine("3: Thread ID: " + Thread.CurrentThread.ManagedThreadId);

Я бы этого не ожидал:

2: Thread ID: 10
3: Thread ID: 11

Что дает? Почему идентификатор потока для продолжения отличается от потока пользовательского интерфейса?

В соответствии с этой статьей [^] мне нужно будет явно вызвать ConfigureAwait, чтобы изменить поведение контекста продолжения!

4b9b3361

Ответ 1

Когда вы await, по умолчанию оператор await будет захватывать текущий "контекст" и использовать его для возобновления метода async.

Этот "контекст" равен SynchronizationContext.Current, если он не равен null, и в этом случае он TaskScheduler.Current. (Если в настоящее время нет текущей задачи, то TaskScheduler.Current совпадает с TaskScheduler.Default, планировщиком задач пула потоков).

Важно отметить, что a SynchronizationContext или TaskScheduler не обязательно подразумевает конкретный поток. Пользовательский интерфейс SynchronizationContext будет планировать работу с потоком пользовательского интерфейса; но ASP.NET SynchronizationContext не будет планировать работу для определенного потока.

Я подозреваю, что причиной вашей проблемы является то, что вы вызываете код async слишком рано. Когда приложение запускается, у него просто обычный обычный поток. Этот поток становится только потоком пользовательского интерфейса, когда он делает что-то вроде Application.Run.

Ответ 2

В выражении await будет использоваться значение SynchronizationContext.Current, чтобы вернуть поток управления обратно в поток, на котором он произошел. В случаях, когда это значение null, оно по умолчанию будет TaskScheduler.Current. Реализация опирается исключительно на это значение, чтобы изменить контекст потока, когда значение Task завершено. Похоже, что в этом случае await захватывает контекст, который не связан с потоком пользовательского интерфейса