C#异步方法调用一直到Main

C#异步方法调用一直到Main,c#,async-await,C#,Async Await,有人能澄清一下这个例子吗?当然,这个例子不起作用: class Program { static void Main(string[] args)//main cant' be async { int res = test();//I must put await here Console.WriteLine("END"); } public async static Task<int> test() { /

有人能澄清一下这个例子吗?当然,这个例子不起作用:

class Program
{
    static void Main(string[] args)//main cant' be async
    {
        int res = test();//I must put await here

        Console.WriteLine("END");
    }

    public async static Task<int> test()
    { //why can't I make it just: public int test()??
        int a1, a2, a3, a4;

        a1 = await GetNumber1();
        a2 = await GetNumber2();
        a3 = await GetNumber3();

        a4 = a1 + a2 + a3;
        return a4;
    }

    public static async Task<int> GetNumber1()
    {
        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("GetNumber1");
                    System.Threading.Thread.Sleep(100);
                }
            });
        return 1;
    }
如何使方法ReserveAHolliday同步?
我是否遗漏了什么或者不理解异步等待机制的用法?

您的异步需要从某个地方开始,因为您的程序有一个起点,所以在这一点上它是一个同步方法。大多数的
async
都是从我们喜欢称之为
async void
的方法开始的,这基本上就是激发和遗忘方法。它开始一项任务,并不关心它返回什么。如果需要在同步方法中等待某些内容,可以对任务使用
.wait()
方法,或使用
.Result
获取任务的结果

对于您的现实世界示例,如果希望同时运行两个任务,则需要执行以下操作:

public async Task<bool> ReserveAHoliday()
{
        //Initialize and start this task
        Task<bool> hotelTask = ReserveAHotel();//HTTP async request
        //Initialize and start this task
        Task<bool> flightTask = ReserveFlight();////HTTP async request
        //Await until hotel task is done, and get the bool
        bool hotelOK = await hotelTask;
        //Await until flight task is done (This might have already finished while the hotel was grabbing, and get the bool
        bool flightOK = await flightTask;
        bool result = hotelOK && flightOK;
        //Return the final result
        return result;
}
class Program
{
    static void Main(string[] args)
    {
        var task = test();
        task.Wait(); //this stops async behaviour
        int result = task.Result;// get return value form method "test"
        Console.WriteLine("RESULT IS = " + result);
    }

    public async static Task<int> test()
    {
        int a1, a2, a3, a4;

        //run all tasks
        //all tasks are doing their job "at the same time"
        var taskA1 = GetNumber1();
        var taskA2 = GetNumber2();
        var taskA3 = GetNumber3();

        //wait for task results
        //here I am collecting results from all tasks
        a1 = await taskA1;
        a2 = await taskA2;
        a3 = await taskA3;

        //get value from all task results
        a4 = a1 + a2 + a3;
        return a4;
    }

    public static async Task<int> GetNumber1()
    {
        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("GetNumber1");
                    System.Threading.Thread.Sleep(100);
                }
            });
        return 1;
    }
    static async Task Main(string[] args)
    {
        await MyMethod();
        await MyOtherMethod();
        Console.WriteLine("Done!");
    }

    private static async Task MyMethod()
    {
        // do something
        await Task.CompletedTask;
    }

    private static async Task MyOtherMethod()
    {
        // do something
        await Task.CompletedTask;
    }
<Project Sdk="Microsoft.NET.Sdk">    
 <PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>netcoreapp2.1</TargetFramework>
  <LangVersion>latest</LangVersion>
 </PropertyGroup>   
</Project>
public async Task ReserveAHoliday()
{
//初始化并启动此任务
Task hotelTask=ReserveAHotel();//HTTP异步请求
//初始化并启动此任务
Task flightTask=ReserveFlight();///HTTP异步请求
//等待酒店任务完成,然后拿到订单
bool hotelOK=等待hotelTask;
//等待飞行任务完成(这可能已经在酒店抓取时完成,并获取bool)
bool flightOK=等待flightTask;
bool result=hotelOK&&flightOK;
//返回最终结果
返回结果;
}

我强烈推荐观看。它很好地介绍了异步的工作原理,可以让您在异步的奇妙世界中一跃而起。

感谢FrankerZ给出了正确的答案! 因此,我的litle示例应该如下所示:

public async Task<bool> ReserveAHoliday()
{
        //Initialize and start this task
        Task<bool> hotelTask = ReserveAHotel();//HTTP async request
        //Initialize and start this task
        Task<bool> flightTask = ReserveFlight();////HTTP async request
        //Await until hotel task is done, and get the bool
        bool hotelOK = await hotelTask;
        //Await until flight task is done (This might have already finished while the hotel was grabbing, and get the bool
        bool flightOK = await flightTask;
        bool result = hotelOK && flightOK;
        //Return the final result
        return result;
}
class Program
{
    static void Main(string[] args)
    {
        var task = test();
        task.Wait(); //this stops async behaviour
        int result = task.Result;// get return value form method "test"
        Console.WriteLine("RESULT IS = " + result);
    }

    public async static Task<int> test()
    {
        int a1, a2, a3, a4;

        //run all tasks
        //all tasks are doing their job "at the same time"
        var taskA1 = GetNumber1();
        var taskA2 = GetNumber2();
        var taskA3 = GetNumber3();

        //wait for task results
        //here I am collecting results from all tasks
        a1 = await taskA1;
        a2 = await taskA2;
        a3 = await taskA3;

        //get value from all task results
        a4 = a1 + a2 + a3;
        return a4;
    }

    public static async Task<int> GetNumber1()
    {
        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("GetNumber1");
                    System.Threading.Thread.Sleep(100);
                }
            });
        return 1;
    }
    static async Task Main(string[] args)
    {
        await MyMethod();
        await MyOtherMethod();
        Console.WriteLine("Done!");
    }

    private static async Task MyMethod()
    {
        // do something
        await Task.CompletedTask;
    }

    private static async Task MyOtherMethod()
    {
        // do something
        await Task.CompletedTask;
    }
<Project Sdk="Microsoft.NET.Sdk">    
 <PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>netcoreapp2.1</TargetFramework>
  <LangVersion>latest</LangVersion>
 </PropertyGroup>   
</Project>
类程序
{
静态void Main(字符串[]参数)
{
var task=test();
task.Wait();//这将停止异步行为
int result=task.result;//从方法“test”获取返回值
Console.WriteLine(“RESULT IS=“+RESULT”);
}
公共异步静态任务测试()
{
int a1、a2、a3、a4;
//运行所有任务
//所有任务“同时”完成各自的工作
var taskA1=GetNumber1();
var taskA2=GetNumber2();
var taskA3=GetNumber3();
//等待任务结果
//在这里,我收集所有任务的结果
a1=等待任务a1;
a2=等待任务a2;
a3=等待任务a3;
//从所有任务结果中获取价值
a4=a1+a2+a3;
返回a4;
}
公共静态异步任务GetNumber1()
{
等待任务。运行(()=>
{
对于(int i=0;i<10;i++)
{
控制台写入线(“GetNumber1”);
系统线程线程睡眠(100);
}
});
返回1;
}
//其他方法也可以使用,因为它们与GetNumber1相同
}

为了在方法中使用
wait
关键字,它必须是
async
。这是一个设计决策,使其更容易向后兼容

Main
不能是
async
,因为它是程序的起点,所以您通常需要以某种方式阻止程序运行。您可以通过在
任务上阻止
或调用
控制台.ReadLine
来实现

任务通常在后台线程上执行,如果所有前台线程都停止,后台线程不会保持程序运行


我在
async await

上有一篇介绍性的博客文章,如果在其中使用await关键字,ReserveAHolliday方法就不能同步

可能的方法是简单地阻塞,直到两个异步方法都返回它们的值。但我不建议这样做,因为这可能导致死锁或其他意外错误

如果您没有同步上下文(例如控制台应用程序),您只需编写

bool hotelOK = ReserveAHotel().Result;
但我认为您最终想要创建一个GUI。这就是阻塞的原因。因为UI应用程序(表单和WPF)确实有一个上下文,等待异步方法会导致死锁

这个问题有一些解决方法,但它们高度依赖于应用程序的设计

编辑:

如果库代码需要同步上下文,那么阻塞肯定会导致死锁

如果您不需要它,可以在库代码中使用
ConfigureAwait(false)
,从而避免阻塞

我的建议是:始终异步/等待或根本不异步/等待。还有其他可能使您的代码异步,例如:基于事件,但就像生活中的任何事情都有利弊一样


请阅读Stephen Cleary的文章。他解释了为什么阻止异步代码会死锁以及如何避免死锁。

下面是一个完整的示例。您可以从MAIN(取决于注释的行)同步(bool r=reserveaholiday().Result;)和异步(只需调用reserveaholiday();)运行Reserveaholiday。您可以看到效果(“结束”在预订完成之前/之后打印)。 我更喜欢wait Task.WhenAll()方法,它更具可读性。 还请注意,在GetNumber1中最好使用wait Task.Delay(100)而不是Thread.sleep

    class Program
{
    static void Main(string[] args)//main cant' be async
    {
        //int res = test().Result;//I must put await here
        bool r = ReserveAHolliday().Result; //this will run Synchronously.
        //ReserveAHolliday(); //this option will run aync : you will see "END" printed before the reservation is complete.
        Console.WriteLine("END");
        Console.ReadLine();
    }

    public async static Task<int> test()
    { //why can't I make it just: public int test()??
        //becuase you cannot use await in synchronous methods. 
        int a1, a2, a3, a4;

        a1 = await GetNumber1();
        a2 = await GetNumber1();
        a3 = await GetNumber1();

        a4 = a1 + a2 + a3;
        return a4;
    }

    public static async Task<int> GetNumber1()
    {
        //await Task.Run(() =>
        //    {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("GetNumber1");
                    await Task.Delay(100); // from what I read using Task.Delay is preferred to using  System.Threading.Thread.Sleep(100);
                }
        //    });
        return 1;
    }

    public async static Task<bool> ReserveAHolliday()
    {
        //bool hotelOK = await ReserveAHotel();//HTTP async request
        //bool flightOK = await ReserveAHotel();////HTTP async request
        var t1 = ReserveAHotel("FirstHotel");
        var t2 = ReserveAHotel("SecondHotel");
        await Task.WhenAll(t1, t2);
        bool result = t1.Result && t1.Result;// hotelOK && flightOK;
        return result;
    }
    public static async Task<bool> ReserveAHotel(string name)
    {
        Console.WriteLine("Reserve A Hotel started for "+ name);
        await Task.Delay(3000);
        if (name == "FirstHotel") 
            await Task.Delay(500); //delaying first hotel on purpose.
        Console.WriteLine("Reserve A Hotel done for " + name);
        return true;
    }
}
类程序
{
静态void Main(字符串[]args)//Main不能是异步的
{
//int res=test().Result;//我必须把wait放在这里
bool r=reserveaholiday().Result;//这将同步运行。
//ReserveAHolliday();//此选项将运行aync:您将看到在预订完成之前打印的“结束”。
控制台。写入线(“结束”);
Console.ReadLine();
}
公共异步静态任务测试()
{//为什么我不能只做:public int test()??
//因为不能在同步方法中使用wait。
int a1、a2、a3、a4;
a1=等待GetNumber1();
a2=等待GetNumber1()