我对使用async修饰符进行异步编程并不熟悉。我试图弄清楚如何确保我的控制台应用程序的主要方法实际上是异步运行的。

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方法上指定异步修饰符,我如何在Main中异步运行代码?


当前回答

对于从Main异步调用任务,使用

Task.Run()用于。net 4.5 Task.Factory.StartNew() for .NET 4.0(可能需要Microsoft.Bcl.Async库用于async和await关键字)

细节: http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx

其他回答

当你在调用堆栈的某个地方调用一个函数,试图重新加入当前线程(被卡在等待中)时,为了避免冻结,你需要做以下事情:

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        List<TvChannel> list = Task.Run((Func<Task<List<TvChannel>>>)bs.GetList).Result;
    }
}

(转换仅用于解决歧义)

当c# 5 CTP被引入时,你当然可以用async…尽管这样做通常不是个好主意。我相信这是在VS 2013的发布中改变的,成为一个错误。

除非你已经启动了任何其他前台线程,否则你的程序将在Main完成时退出,即使它已经启动了一些后台工作。

你到底想做什么?请注意,你的GetList()方法目前真的不需要是异步的——它添加了一个额外的层,没有真正的原因。它在逻辑上等价于(但比):

public Task<List<TvChannel>> GetList()
{
    return new GetPrograms().DownloadTvChannels();
}

我将添加一个所有其他答案都忽略了的重要功能:取消。

TPL的一大特点是支持取消功能,控制台应用有内置的取消功能(CTRL+C)。把它们结合在一起很简单。这是我如何构建所有异步控制台应用程序:

static void Main(string[] args)
{
    CancellationTokenSource cts = new CancellationTokenSource();
    
    System.Console.CancelKeyPress += (s, e) =>
    {
        e.Cancel = true;
        cts.Cancel();
    };

    MainAsync(args, cts.Token).GetAwaiter.GetResult();
}

static async Task MainAsync(string[] args, CancellationToken token)
{
    ...
}

不确定这是否是你要找的,但我想等待加载方法。我最终使用main_shows处理程序,并使它异步:

private async void Main_Shown(object sender, EventArgs e)
{
   await myAsyncMethod();
}

在Main中尝试将GetList调用更改为:

Task.Run(() => bs.GetList());