IWebHost: вызов Run() против RunAsync()

Когда создается новый проект ASP.NET Core 2.0, шаблон Main метод в Program класс выглядит примерно так:

public static void Main(string[] args)
{
    BuildWebHost(args).Run(); // BuildWebHost returns an IWebHost
}

Но так как C# 7.1, Main Метод может быть асинхронным методом, возвращающим Task вместо void, Это означает, что намного проще вызвать асинхронный метод внутри Main,

Итак RunAsync() на IWebHost можно вызвать внутри Main вместо Run() метод. Что-то вроде этого:

public static async Task Main(string[] args)
{
    await BuildWebHost(args).RunAsync().ConfigureAwait(false);
}

Согласно документации, Run метод:

Запускает веб-приложение и блокирует вызывающий поток до отключения хоста.

Тогда как RunAsync метод:

Запускает веб-приложение и возвращает задание, которое завершается только при запуске токена или при завершении работы.

Мне было интересно, когда RunAsync метод будет использоваться вместо обычного Run метод? Каковы практические последствия этого? Заметит ли конечный пользователь какую-либо разницу?

2 ответа

Решение

Шаблоны ASP.NET Core по умолчанию содержат следующее Main метод:

public static void Main(string[] args)
{
    BuildWebHost(args).Run();
}

Тот Run метод есть WebHostExtensions.Run метод расширения, который реализован так:

public static void Run(this IWebHost host)
{
    host.RunAsync().GetAwaiter().GetResult();
}

Так что это на самом деле называет WebHostExtensions.RunAsync и просто блокирует его.


Теперь давайте посмотрим, как C# 7.1 асинхронный Main указывается метод:

Когда один из [этих методов на основе задач] идентифицируется как точка входа, компилятор синтезирует фактический метод точки входа, который вызывает один из этих кодированных методов:

  • static Task Main() приведет к компиляции, испускающей эквивалент private static void $GeneratedMain() => Main().GetAwaiter().GetResult();
  • static Task Main(string[]) приведет к компиляции, испускающей эквивалент private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();

Так что в основном, имея асинхронный Main метод как это:

public static async Task Main(string[] args)
{
    await BuildWebHost(args).RunAsync();
}

Заставит компилятор также выдавать следующее:

private static void $GeneratedMain(string[] args)
{
    Main(args).GetAwaiter().GetResult();
}

И если вы посмотрите внимательно на то, что происходит с возвращенной задачей, это почти то же самое, что и WebHostExtensions.Run метод делает.

Так что это значит? Вы можете использовать любое из этих решений, и эффект будет одинаковым. Ваше приложение будет правильно блокироваться, пока асинхронная задача не будет решена. Нет практического различия между решениями. Единственное реальное преимущество, которое вы получили бы от использования асинхронного метода main, было бы, если бы у вас была другая асинхронная работа в Main Способ; хотя это, вероятно, будет очень редким случаем, поскольку для веб-приложений вы, скорее всего, будете выполнять настройку в течение жизненного цикла приложения ASP.NET Core (т. е. в Startup и не за его пределами).

Каковы практические последствия этого? Заметит ли конечный пользователь какую-либо разницу?

Нет никакой разницы в поведении уровня RunTime.

Поскольку эта функция не соответствует изменению кода CLR, асинхронный метод Main является всего лишь синтаксическим сахаром. Такая конструкция обеспечивает совместимость с предыдущими версиями языка. Чтобы узнать больше подробностей, см. Async Main в репо Roslyn Git.
- Серия C# 7, часть 2: Асинхронное соединение

Другие вопросы по тегам