JIT-компиляцией (just-in-time), при котором каждая отдельная функция компилируется при первом запуске.
Если вы пишете библиотеки, то в большинстве случаев следует вызывать ConfigureAwait(false) везде, где используется await. Это связано с тем, что продолжение через контекст синхронизации может быть затратным, а в некоторых случаях способно привести к взаимоблокировке. Единственным исключением являются случаи, когда вы делаете что-то, что определенно требует сохранения контекста синхронизации, или же вы точно знаете, что ваша библиотека всегда будет использоваться только в средах приложений, которые не устанавливают контекст синхронизации. (Например, приложения ASP.NET Core не используют контексты синхронизации, поэтому обычно не имеет значения, вызываете ли вы в них ConfigureAwait(false).)
Простейшая реализация шаблона await
public class MyAwaitableType
{
public MinimalAwaiter GetAwaiter()
{
return new MinimalAwaiter();
}
public class MinimalAwaiter : INotifyCompletion
{
public bool IsCompleted => true;
public string GetResult() => "This is a result";
public void OnCompleted(Action continuation)
{
throw new NotImplementedException();
}
}
}
Листинг 17.15 показывает минимальную рабочую реализацию шаблона await. Она чрезмерно упрощена, так как всегда завершается синхронно, поэтому ее метод OnCompleted ничего не делает. Фактически при использовании шаблона await этот метод никогда не будет вызываться, поэтому у меня он вызывает исключение. И хотя этот пример крайне прост, он служит прекрасной иллюстрацией того, что делает await
Различие между этими интерфейсами и их соответствующими методами заключается в том, что первый требует, чтобы ожидающий передавал текущий контекст выполнения целевому методу, а последний — нет.
Вам придется реализовать INotifyCompletion, а еще есть дополнительный интерфейс, который тоже рекомендуется по возможности реализовать. Он называется ICriticalNotifyCompletion. Они выполняют похожие задачи: каждый определяет один метод (OnCompleted и UnsafeOnCompleted соответственно), который принимает единственный делегат Action, и ожидающий должен вызывать этот делегат после завершения операции.
Компилятору также нужен способ получить результат после завершения работы, поэтому у ожидающего должен быть метод GetResult. Его возвращаемый тип определяет тип результата операции — это будет тип выражения await.
тот метод должен возвращать объект или значение, которое называется ждущим и выполняет три действия.
Во-первых, ждущий объект должен предоставить свойство типа bool с именем IsCompleted.
Компилятор ожидает, что операнд ключевого слова await будет типом, который содержит метод с именем GetAwaiter.
Вызов пользовательской реализации await
static async Task UseCustomAsync()
{
string result = await CustomAsync();
Console.WriteLine(result);
}
public static MyAwaitableType CustomAsync()
{
return new MyAwaitableType();
}