Как получить задачу, использующую SynchronizationContext? И как в любом случае используется SynchronizationContext?
Я все еще изучаю всю концепцию Task и TPL. Из моего текущего понимания функции SynchronizationContext (если они есть) используются await
для отправки задачи "где-то". С другой стороны, функции класса Task
не используют контекст, правильно?
Итак, например Task.Run(...)
всегда будет отправлять действие в рабочий поток пула потоков и полностью игнорировать SynchronizationContext.Current
. await Foobar()
будет использовать контекст для выполнения сгенерированной задачи после await
?
Если это так, то мой вопрос: как я могу получить Task
, который фактически запускает действие, но отправляется с помощью SynchronizationContext.Current.Send/Post
?
И может ли кто-нибудь рекомендовать хорошее введение в SynchronizationContext
, особенно когда и как они используются остальной частью фреймворка? MSDN кажется очень спокойным относительно класса. Верхние хиты Google (здесь и здесь) кажутся с учетом только диспетчеризации Windows Forms. Стивен Клири написал статью статью, в которой приятно узнать, какие контексты уже существуют и как они работают, но мне не хватает понимания того, где и когда они фактически используются.
Ответы
Ответ 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
.