如何在Main中调用异步方法?


77
public class test
{
    public async Task Go()
    {
        await PrintAnswerToLife();
        Console.WriteLine("done");
    }

    public async Task PrintAnswerToLife()
    {
        int answer = await GetAnswerToLife();
        Console.WriteLine(answer);
    }

    public async Task<int> GetAnswerToLife()
    {
        await Task.Delay(5000);
        int answer = 21 * 2;
        return answer;
    }
}

如果要在main()方法中调用Go,该怎么办?我正在尝试C#的新功能,我知道我可以将异步方法挂接到事件上,并通过触发该事件,可以调用异步方法。

但是,如果我想直接在main方法中调用该怎么办?我怎样才能做到这一点?

我做了类似的事情

class Program
{
    static void Main(string[] args)
    {
        test t = new test();
        t.Go().GetAwaiter().OnCompleted(() =>
        {
            Console.WriteLine("finished");
        });
        Console.ReadKey();
    }


}

但是似乎这是一个死锁,屏幕上没有任何内容。


似乎我发现了问题,cos GetAwaiter()。OnCompleted()将立即返回主函数,因此,在调用Console.Readkey()时,主线程处于阻塞状态,因此无法将任务返回的输出消息打印到屏幕上因为它正在等待主线程解除阻塞。如果我用while(true)替换Console.readkey(){Thread.Sleep(1000); }效果很好。
拉里

我无法重现您的死锁问题,但是,如果有人在乎..尝试使用Go().ConfigureAwait(false).GetAwaiter()异步方法中的新上下文。
arviman

Answers:


100

您的Main方法可以简化。对于C#7.1及更高版本:

static async Task Main(string[] args)
{
    test t = new test();
    await t.Go();
    Console.WriteLine("finished");
    Console.ReadKey();
}

对于早期版本的C#:

static void Main(string[] args)
{
    test t = new test();
    t.Go().Wait();
    Console.WriteLine("finished");
    Console.ReadKey();
}

这是async关键字(及相关功能)之美的一部分:大大减少或消除了回调的使用和混乱。


@MarcGravell我已将新方法结合到我的答案中。DavidG的答案提供了更多细节,但我不再过时了。👍
蒂姆·S.

您可能需要修改项目文件,以允许使用c#7.0及更高版本。答案发布在这里
路加福音

26

最好不要使用Wait, new test().Go().GetAwaiter().GetResult() 因为这样可以避免将异常包装到AggregateExceptions中,因此您可以像平常一样用try catch(Exception ex)块包围Go()方法。



不要在异步方法上调用GetResult()。这将阻塞主线程。这不仅违反了异步方法的目的,而且还为死锁留出了空间。
Ruchira

21

自从C#v7.1版本发布以来,async main就可以使用方法,从而避免了已经发布的答案中的变通方法。添加了以下签名:

public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);

这使您可以像这样编写代码:

static async Task Main(string[] args)
{
    await DoSomethingAsync();
}

static async Task DoSomethingAsync()
{
    //...
}

2
我正在尝试static async Task Main(string[] args),但出现错误CS5001 Program does not contain a static 'Main' method suitable for an entry point。我已经检查了项目属性,并且下拉列表中没有可用的启动对象。使用VS2017 + .NET Core 2.0的最新更新。我该如何克服?
NightOwl888 '18

@ NightOwl888您可以在项目属性中看到C#7.1吗?
DavidG '18 -4-12

4
是的,我可以,谢谢。默认设置为“最新主要版本”,因此默认设置为7.0。我改为7.1,现在可以编译了。
NightOwl888 '18

12
class Program
{
    static void Main(string[] args)
    {
       test t = new test();
       Task.Run(async () => await t.Go());
    }
}

1
此答案将创建一个后台线程,如果前台线程先完成,则可能导致问题
Luke

11

只要您正在从返回的任务访问结果对象,就根本不需要使用GetAwaiter(仅在访问结果的情况下)。

static async Task<String> sayHelloAsync(){

       await Task.Delay(1000);
       return "hello world";

}

static void main(string[] args){

      var data = sayHelloAsync();
      //implicitly waits for the result and makes synchronous call. 
      //no need for Console.ReadKey()
      Console.Write(data.Result);
      //synchronous call .. same as previous one
      Console.Write(sayHelloAsync().GetAwaiter().GetResult());

}

如果要等待任务完成并做进一步处理:

sayHelloAsyn().GetAwaiter().OnCompleted(() => {
   Console.Write("done" );
});
Console.ReadLine();

如果您有兴趣从sayHelloAsync获取结果并对其进行进一步处理:

sayHelloAsync().ContinueWith(prev => {
   //prev.Result should have "hello world"
   Console.Write("done do further processing here .. here is the result from sayHelloAsync" + prev.Result);
});
Console.ReadLine();

等待功能的最后一种简单方法是:

static void main(string[] args){
  sayHelloAsync().Wait();
  Console.Read();
}

static async Task sayHelloAsync(){          
  await Task.Delay(1000);
  Console.Write( "hello world");

}

这需要在其方法的详细信息选择和为什么
乔·菲利普斯

4
public static void Main(string[] args)
{
    var t = new test();
    Task.Run(async () => { await t.Go();}).Wait();
}

4
在回答时,请始终详细说明为什么它是所提出问题的“答案”。
Prasoon Karunan V '18 -4-7

1

使用.Wait()

static void Main(string[] args){
   SomeTaskManager someTaskManager  = new SomeTaskManager();
   Task<List<String>> task = Task.Run(() => marginaleNotesGenerationTask.Execute());
   task.Wait();
   List<String> r = task.Result;
} 

public class SomeTaskManager
{
    public async Task<List<String>> Execute() {
        HttpClient client = new HttpClient();
        client.BaseAddress = new Uri("http://localhost:4000/");     
        client.DefaultRequestHeaders.Accept.Clear();           
        HttpContent httpContent = new StringContent(jsonEnvellope, Encoding.UTF8, "application/json");
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        HttpResponseMessage httpResponse = await client.PostAsync("", httpContent);
        if (httpResponse.Content != null)
        {
            string responseContent = await httpResponse.Content.ReadAsStringAsync();
            dynamic answer = JsonConvert.DeserializeObject(responseContent);
            summaries = answer[0].ToObject<List<String>>();
        }
    } 
}

0

尝试“结果”属性

class Program
{
    static void Main(string[] args)
    {
        test t = new test();
        t.Go().Result;
        Console.ReadKey();
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.