Как получить задачу, использующую SynchronizationContext? И как в любом случае используется SynchronizationContext? - программирование
Подтвердить что ты не робот

Как получить задачу, использующую SynchronizationContext? И как в любом случае используется SynchronizationContext?

Я все еще изучаю всю концепцию Task и TPL. Из моего текущего понимания функции SynchronizationContext (если они есть) используются await для отправки задачи "где-то". С другой стороны, функции класса Task не используют контекст, правильно?

Итак, например Task.Run(...) всегда будет отправлять действие в рабочий поток пула потоков и полностью игнорировать SynchronizationContext.Current. await Foobar() будет использовать контекст для выполнения сгенерированной задачи после await?

Если это так, то мой вопрос: как я могу получить Task, который фактически запускает действие, но отправляется с помощью SynchronizationContext.Current.Send/Post?

И может ли кто-нибудь рекомендовать хорошее введение в SynchronizationContext, особенно когда и как они используются остальной частью фреймворка? MSDN кажется очень спокойным относительно класса. Верхние хиты Google (здесь и здесь) кажутся с учетом только диспетчеризации Windows Forms. Стивен Клири написал статью статью, в которой приятно узнать, какие контексты уже существуют и как они работают, но мне не хватает понимания того, где и когда они фактически используются.

4b9b3361

Ответ 1

Как я могу получить задачу, которая фактически запускает действие, но отправляется с использованием SynchronizationContext.Current.Send/Post?

Использовать специальный планировщик задач:

Task.Factory.StartNew(
    () => {}, // this will use current synchronization context
    CancellationToken.None, 
    TaskCreationOptions.None, 
    TaskScheduler.FromCurrentSynchronizationContext());

И кто-нибудь может рекомендовать хорошее введение в SynchronizationContext

Посмотрите статью Все о SynchronizationContext Стивена Клири.

Ответ 2

Когда вы это изучаете, важно указать, что Task, используемый TPL, отличается от Task как используется async/await, даже если они одного типа. Например, TPL обычно использует родительские/дочерние задачи, но async/await не делает.

TPL использует планировщики задач для выполнения своих задач. Как отметил Деннис, TaskScheduler.FromCurrentSynchronizationContext предоставит вам планировщик задач, который использует Post для текущего SynchronizationContext для выполнения своей задачи.

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

Деннис указал на способ TPL планирования задачи на текущий SynchronizationContext, но в мире async/await, этот подход не требуется. Скорее, вы можете явно планировать задачи в пуле потоков через Task.Run:

async Task MyMethodAsync()
{
  // Whee, on a SynchronizationContext here!
  await Task.Run(() => { }); // Ooo, on the thread pool!
  // Back on the SynchronizationContext ...
  //  ... automagically!
}

Я написал свою статью SynchronizationContext именно потому, что документы MSDN так не хватало. У меня есть немного больше информации о моем блоге, но все важные биты находятся в статье MSDN. Многие типы используют AsyncOperation, а не SynchronizationContext напрямую; лучшая документация для этого похожа на документы EAP (раздел "Threading and Context" ). Но я должен также указать, что EAP фактически устарел из-за async/await, поэтому я не буду писать код, используя AsyncOperation (или SynchronizationContext) - если только я не писал собственный SynchronizationContext.