Что означает "контекст" в коде С# 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 фиксируется точно так же, как если бы он ссылался на выражение лямбда.