无法在控制台应用程序的“主要"方法上指定“异步"修饰符 [英] Can't specify the 'async' modifier on the 'Main' method of a console app

查看:22
本文介绍了无法在控制台应用程序的“主要"方法上指定“异步"修饰符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是使用 async 修饰符进行异步编程的新手.我试图弄清楚如何确保我的控制台应用程序的 Main 方法实际上是异步运行的.

I am new to asynchronous programming with the async modifier. I am trying to figure out how to make sure that my Main method of a console application actually runs asynchronously.

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = bs.GetList();
    }
}

public class Bootstrapper {

    public async Task<List<TvChannel>> GetList()
    {
        GetPrograms pro = new GetPrograms();

        return await pro.DownloadTvChannels();
    }
}

我知道这不是从顶部"异步运行的.由于无法在 Main 方法上指定 async 修饰符,如何在 main 中异步运行代码?

I know this is not running asynchronously from "the top." Since it is not possible to specify the async modifier on the Main method, how can I run code within main asynchronously?

推荐答案

正如您所发现的,在 VS11 中,编译器将不允许 async Main 方法.这在带有异步 CTP 的 VS2010 中是允许的(但从不推荐).

As you discovered, in VS11 the compiler will disallow an async Main method. This was allowed (but never recommended) in VS2010 with the Async CTP.

我最近发布了关于 async/await异步控制台程序.以下是介绍帖子中的一些背景信息:

I have recent blog posts about async/await and asynchronous console programs in particular. Here's some background info from the intro post:

如果等待"看到 awaitable 尚未完成,然后它异步执行.它告诉 awaitable 在完成时运行该方法的其余部分,然后从异步方法 返回.当 Await 将方法的其余部分传递给 awaitable 时,它​​也会捕获当前的 context.

If "await" sees that the awaitable has not completed, then it acts asynchronously. It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method. Await will also capture the current context when it passes the remainder of the method to the awaitable.

稍后,当 awaitable 完成时,它将执行 async 方法的其余部分(在捕获的上下文中).

Later on, when the awaitable completes, it will execute the remainder of the async method (within the captured context).

这就是为什么在带有 async Main 的控制台程序中出现此问题的原因:

Here's why this is a problem in Console programs with an async Main:

请记住,在我们的介绍文章中,异步方法将在完成之前返回给它的调用者.这在 UI 应用程序(该方法只返回 UI 事件循环)和 ASP.NET 应用程序(该方法从线程返回但保持请求活动)中非常有效.控制台程序的效果不是很好:Main 返回操作系统 - 因此您的程序退出.

Remember from our intro post that an async method will return to its caller before it is complete. This works perfectly in UI applications (the method just returns to the UI event loop) and ASP.NET applications (the method returns off the thread but keeps the request alive). It doesn't work out so well for Console programs: Main returns to the OS - so your program exits.

一种解决方案是提供您自己的上下文 - 一个主循环";用于异步兼容的控制台程序.

One solution is to provide your own context - a "main loop" for your console program that is async-compatible.

如果您有一台带有 Async CTP 的机器,您可以使用 My DocumentsMicrosoft Visual Studio Async CTPSamples(C# Testing) Unit TestingAsyncTestUtilities 中的 GeneralThreadAffineContext.或者,您可以使用 AsyncContext 来自 我的 Nito.AsyncEx NuGet 包.

If you have a machine with the Async CTP, you can use GeneralThreadAffineContext from My DocumentsMicrosoft Visual Studio Async CTPSamples(C# Testing) Unit TestingAsyncTestUtilities. Alternatively, you can use AsyncContext from my Nito.AsyncEx NuGet package.

这是一个使用 AsyncContext 的示例;GeneralThreadAffineContext 的用法几乎相同:

Here's an example using AsyncContext; GeneralThreadAffineContext has almost identical usage:

using Nito.AsyncEx;
class Program
{
    static void Main(string[] args)
    {
        AsyncContext.Run(() => MainAsync(args));
    }

    static async void MainAsync(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

或者,您可以阻塞主控制台线程,直到异步工作完成:

Alternatively, you can just block the main Console thread until your asynchronous work has completed:

class Program
{
    static void Main(string[] args)
    {
        MainAsync(args).GetAwaiter().GetResult();
    }

    static async Task MainAsync(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

注意GetAwaiter().GetResult()的使用;这可以避免使用 Wait()Result 时发生的 AggregateException 包装.

Note the use of GetAwaiter().GetResult(); this avoids the AggregateException wrapping that happens if you use Wait() or Result.

2017 年 11 月 30 日更新: 从 Visual Studio 2017 更新 3 (15.3) 开始,该语言现在支持 async Main - 只要它返回 <代码>任务或<代码>任务<T>.所以你现在可以这样做了:

Update, 2017-11-30: As of Visual Studio 2017 Update 3 (15.3), the language now supports an async Main - as long as it returns Task or Task<T>. So you can now do this:

class Program
{
    static async Task Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

语义似乎与阻塞主线程的 GetAwaiter().GetResult() 样式相同.但是,目前还没有 C# 7.1 的语言规范,所以这只是一个假设.

The semantics appear to be the same as the GetAwaiter().GetResult() style of blocking the main thread. However, there's no language spec for C# 7.1 yet, so this is only an assumption.

这篇关于无法在控制台应用程序的“主要"方法上指定“异步"修饰符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆