2016-10-25 4 views
5

, основанного на том, что я прочитал на MSDNасинхронный ждет и нарезания резьба

Асинхронных и жду ключевых слова не вызывают дополнительные нити, чтобы быть созданы. Асинхронные методы не требуют многопоточности, поскольку метод async не запускается в своем потоке. Метод работает в текущем контексте синхронизации и использует время в потоке только тогда, когда активен метод . Вы можете использовать Task.Run, чтобы переместить работу, связанную с процессором, на фоновый поток , но фоновый поток не помогает с процессом , который просто ждет, когда результаты станут доступными.

В основном говорят, что нить не будет создана. Но внутри класса, который я унаследовал HttpClient я нашел что-то интересное ..

async Task<T> SendAsync<T>(HttpMethod method, Uri uri, HttpContent content, CancellationToken cancellationToken) 
{ 
     HttpRequestMessage msg = new HttpRequestMessage(method, uri); 
     msg.Content = content; 
     //On Main Thread 
     HttpResponseMessage response = await SendAsync(msg, cancellationToken); 
     //On worker thread 
     //... 
} 

метод вызывается внутри static void Main

Task result = client.GetAsync<string>(...); 
//GetAsync calls await SendAsync<T> 
result.Wait(); 

Почему я в отдельном потоке после await SendAsnc вызова ?? Я думал, что асин не создает новую нить. Или, по крайней мере, он будет вызван обратно в исходный поток после ожидания.

+0

Если у вас нет * есть * контекст синхронизации, то продолжение из метода async будет выполняться в потоке threadpool. Консольные приложения (которые я предполагаю это, поскольку вы ссылаетесь на «Main()») по умолчанию не имеют контекста синхронизации. –

ответ

9

Это плохо рекламируется в документации, но способ, которым async/await работает в консольном приложении, очень отличается от того, как он работает в приложении пользовательского интерфейса из-за отсутствия контекста синхронизации в консольном приложении. This article описывает детали и дает пример кода, как добавить один, чтобы асинхронный/ожидающий ведет себя более предсказуемым образом.

Как правило, вы абсолютно правы насчет асинхронном/ждать не обязательно влекущие многопоточность (хотя такие вещи, как Task.Run сделать, на самом деле, вызывает код в вопросе запуска в пуле потоков), но (как описано в статье I, связанной с) в консольном приложении async/await может работать в любом месте.

Моя обычная аналогия того, как работает async при работе в одной и той же ветке, - это думать о том, чтобы пойти в ресторан с 9 другими людьми (всего 10 человек). Когда приходит официант, 9 человек готовы, а 10 - нет. В этом случае официант сначала возьмет остальные 9 человек, а затем вернется к 10-му человеку. Если по какой-то причине 10-го лица действительно Медленно официант всегда мог вернуть заказы на кухню и вернуться, когда готово 10 человек.

Очевидно, что нет смысла привлекать второго официанта, чтобы ждать, пока 10-й парень будет готов к заказу, и было бы явно неэффективно заставить всех остальных ждать, пока один парень будет готов. Добавление дополнительных официантов в ситуацию не ускорит ситуацию, потому что задержка не вызвана нехваткой официантов, это вызвано тем, что 10-летний парень не спешит решиться (и нет ничего, что может подождать,).

6

Описываю это поведение в своем introduction to async blog post.

В целом, это правильно:

Асинхронный и поджидают ключевые слова не вызывают дополнительные потоки, которые будут созданы.

И вот это:

Я думал ASYN не Creats никакой новой нити.

Это не правильно:

Или, по крайней мере, он будет вызван обратно к исходной нити после ОЖИДАНИЯ.

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

По умолчанию await захватывает «контекст», который является текущим SynchronizationContext (если это не null, в этом случае текущий контекст является текущим TaskScheduler). Потоки пользовательского интерфейса имеют свой собственный контекст синхронизации (например, WinFormsSynchronizationContext или DispatcherSynchronizationContext), и в этом случае метод async будет продолжать выполняться в этом же потоке пользовательского интерфейса.

В приложении консоли отсутствует контекст синхронизации, поэтому контекст, выделенный await, будет контекстом пула потоков. Таким образом, когда метод async готов к возобновлению, он будет назначен пулу потоков и подхвачен некоторым потоком.

1

Консольные приложения имеют пул потоков SynchronizationContext вместо синхронного синхронизирующего синхронного текста SynchronizationContext, который используется в приложениях GUI и ASP.Net, поэтому, когда ожидание завершается, он планирует оставшуюся часть метода async на поток потока потока. : this article для получения дополнительной информации о поведении асинхронного ожидания.

Смежные вопросы