Что означает "контекст" в коде С# async/await?
Давайте посмотрим на простой код С# async/await, где у меня есть ссылка на объект (obj
) до и после await
с ConfigureAwait(false)
private async Task<SomeObject> AnAsyncLibraryMethod(SomeObject obj)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
obj.Name = "Harry"; // <-- obj here
// MAIN POINT
var newSubObj = await FetchOverHttpAsync().ConfigureAwait(false);
// Continuation here
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
obj.Name = "Sally"; // <-- same obj here
return obj;
}
public class SomeObject { public string Name; }
ConfigureAwait(false)
, по-видимому, означает НЕ маршал продолжения обратно в исходный контекст, захваченный - нормально, но что это значит? Я пробовал код выше и obj
IS правильно ссылался назад (даже если он возобновляется в другом потоке).
Таким образом, "контекст", по-видимому, не является рабочей областью потока (т.е. локальным хранилищем потоков). Так что же такое "контекст"? Поэтому, что это значит для
Маршал продолжения обратно в исходный контекст, захваченный
Ответы
Ответ 1
Если я не совсем ошибаюсь, ConfigureAwait(false);
означает, что код, который запускает после код, который вы ожидаете, не требуется использовать SynchronizationContext
до дожидаться.
SynchronizationContext
могут быть разными, как указал Стивен. Итак, представьте, что вы находитесь в веб-среде, а ваш код после ожидания полагается на HttpContext.Current.Items, это может не работать больше, если вы установите ConfigureAwait(false);
Следующий код в контроллере MVC генерирует исключение, например
public async Task<ActionResult> Index()
{
System.Web.HttpContext.Current.Items["test"] = "test";
var result = await SomethingAsync();
return View();
}
private async Task<object> SomethingAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
// this will throw a nullpointer if ConfigureAwait is set to false
return System.Web.HttpContext.Current.Items["test"];
}
Ваша переменная, хотя она просто входит в объем метода, и поэтому она будет доступна, в основном, закрытие/область метода, если это имеет смысл?
Ответ 2
Как я описываю в своем async
сообщении блога intro, "контекст":
-
SynchronizationContext.Current
, если это не null
, и в этом случае это
-
TaskScheduler.Current
. Обратите внимание: если нет текущего планировщика задач, то TaskScheduler.Current
совпадает с TaskScheduler.Default
, который представляет собой контекст пула потоков.
В большинстве случаев это либо контекст запроса UI, либо ASP.NET(оба типа SynchronizationContext
), либо это контекст пула потоков. Сценарии планировщика задач редко вступают в игру.
Обратите внимание, что этот контекст используется только для планирования продолжения. Он ничего не делает с маршалингом; в вашем примере obj
фиксируется точно так же, как если бы он ссылался на выражение лямбда.