IWebHost:调用 运行() 与 运行Async()

IWebHost: Calling Run() vs RunAsync()

创建新的 ASP.NET Core 2.0 项目时,Program class 中的样板 Main 方法看起来像这样:

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

但是从 C# 7.1 开始,Main 方法可以是返回 Task 而不是 void 的异步方法。这意味着在 Main.

中调用异步方法要容易得多

因此可以在 Main 中调用 IWebHost 上的 RunAsync() 而不是 Run() 方法。像这样:

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

According to the documentationRun方法:

Runs a web application and block the calling thread until host shutdown.

RunAsync 方法:

Runs a web application and returns a Task that only completes when the token is triggered or shutdown is triggered.

我想知道什么时候应该使用 RunAsync 方法而不是常规的 Run 方法?这有什么实际意义?最终用户会注意到任何不同吗?

What are the practical implications of this? Would the end-user notice any difference?

运行时级别行为没有区别。

Since this feature does not correspond to a CLR code change, the async Main method is just a syntactical sugar. This design allows backend compatibility with the previous versions of the language. To read more details, please see Async Main in the Roslyn Git repo.
- C# 7 Series, Part 2: Async Main

默认 ASP.NET 核心模板包含以下 Main 方法:

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

那个Run方法就是WebHostExtensions.Run extension method which is implemented like this:

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

所以这实际上调用了 WebHostExtensions.RunAsync,只是阻塞了它。


现在,让我们看看 C# 7.1 的异步 Main 方法 is specified:

When one of [these task-based methods] is identified as the entrypoint, the compiler will synthesize an actual entrypoint method that calls one of these coded methods:

  • static Task Main() will result in the compiler emitting the equivalent of private static void $GeneratedMain() => Main().GetAwaiter().GetResult();
  • static Task Main(string[]) will result in the compiler emitting the equivalent of 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 方法中有其他异步工作要做;尽管这可能是非常罕见的情况,因为对于 Web 应用程序,您更有可能在 ASP.NET 核心应用程序的生命周期内进行设置工作(即在 Startup 中,而不是在它之外)。