2015-03-19 3 views
3

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

Рассмотрим следующий пример:

public async void StartThread() 
{ 
    while(true){ 
     SomeOtherClass.SomeSynchronousStuff(); 
     var something = await SomeOtherClass.SomeOtherAsyncMethod(); 
    } 
} 

public void ConstructorForThisClass() 
{ 
    Thread thread = new Thread(StartThread); 
    thread.Start(); 
} 

Мое понимание асинхронном/ожидают, что то, что происходит под одеялом, что компилятор, по сути превращая ваш код в кучу обратных вызовов и сохранения состояния объектов для каждого из них ,

Итак, в соответствии с этим, мои вопросы:

  1. Будет ли вновь созданный поток будет запущен асинхронно? Значит, пока поток ждет SomeOtherAsyncMethod, будет ли он освобожден для работы над другой работой?
  2. Если предыдущее верно, будет ли поток просто заканчиваться, а поток пула потоков займет свое место, когда возвращается SomeOtherAsyncMethod?
  3. Как я могу сделать функцию StartThread в потоке пула потоков, а не в управляемом потоке?
  4. Когда ожидаемый метод возвращается к вызывающему абоненту, он вынужден возобновить поток, который вызывает его, или может ли любая свободная нить занять его место?

ответ

5

Будет ли новый поток работать асинхронно?

Ваша формулировка немного проблематична. Конструкция потока полностью синхронна.

Значение, в то время как поток ожидает SomeOtherAsyncMethod, это будет освобождается для работы на другую работу?

Вы вручную создаете поток, используя класс Thread, а не Threadpool Thread. Он не используется внутри AppDomain. Это будет освободиться после того, как он попадет в первое ключевое слово await, но поскольку вы используете его в бесконечном цикле while, он не будет использоваться для любой другой работы, кроме этого.

Если предыдущий верно, будет нить просто конец и пул потоков нить занять свое место, когда SomeOtherAsyncMethod возвращается?

Не считая прежнего, так как вы не используете ConfigureAwait(false), то продолжение будет выполняться на произвольном потоке ThreadPool. Но это действительно зависит от контекста. Поскольку вы используете этот делегат в новом потоке, вот что происходит. Но если бы вы, скажем, выполнили это из потока пользовательского интерфейса, то продолжение попыталось бы маршировать себя в контуре сообщения пользовательского интерфейса через соответствующий TaskScheduler и соответствующий SynchronizationContext.

Как бы я начал выдавать функцию StartThread в пуле потоков поток, а не управляемый поток?

Все потоки, инициированные Thread класса и ThreadPool класса удалось темы. Если вы имели в виду «Как запустить этот делегат в потоковом пуле», то ответ будет получен через Task.Run или через статический класс ThreadPool.

Когда awaitable метод возвращает его вызывающей, он вынужден возобновить на нити, которая вызывает его или может любой свободный поток занять его место?

Если RAN без ConfigureAwait(false), он вынужден на текущий TaskScheduler и лежащих в его основе SynchronizationContext. Это означает, что если вы запустите внутри цикла сообщений пользовательского интерфейса и вызовете await, он попытается опубликовать его продолжение. Если нет настраиваемого TaskScheduler, он будет использовать значение по умолчанию, которое является планировщиком потоков.

5

Простые нити не работают отлично с async/await.

Будет ли новый поток работать асинхронно? Смысл, пока поток ожидает SomeOtherAsyncMethod, будет ли он освобожден для работы над другой работой?

На самом деле, поток просто выйдет. Когда StartThread возобновится после await, он будет выполняться в потоке пула потоков.

Как бы я начал выдавать функцию StartThread в потоке пула потоков, а не в управляемом потоке?

Во-первых, вы хотите изменить тип возвращаемого StartThread из void в Task. async void методы предназначены для обработчиков событий; использование их в других местах может вызвать всевозможные проблемы.

Тогда вы можете просто назвать его через Task.Run:

var backgroundTask = Task.Run(() => StartThread()); 

Когда awaitable метод возвращает его вызывающей, он вынужден возобновить на резьбе, что его вызывает или может любой свободный поток занять свое место ?

По умолчанию оператор await будет захватить «текущий контекст» и возобновить на этом контексте. Этот «текущий контекст» равен SynchronizationContext.Current, если это не null, и в этом случае это TaskScheduler.Current. Обычно это либо UI/ASP.NET SynchronizationContext, либо это контекст пула потоков (TaskScheduler.Default).

Вы можете найти мой async intro полезный.

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