C # Async method called before Main

Can someone clarify this example, which of course does not work:

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; } 

I am trying to "collect" values ​​from GenNumberX methods using "wait". I would like the test method not asynchronous. I do not understand why the test should be asynchronous when I use to get the value. This example makes me write async for every method that I use async in, and when I iterate over Main, I can not make it async?

How to write an example of the real world:

 public bool ReserveAHolliday() { bool hotelOK = await ReserveAHotel();//HTTP async request bool flightOK = await ReserveFlight();////HTTP async request bool result = hotelOK && flightOK; return result; } 

How to make ReserveAHolliday method synchronous? Am I missing something or do not understand the use of the asynchronous wait mechanism?

+5
source share
5 answers

below is a complete example. you can run ReserverAHoliday as synchronously (bool r = ReserveAHolliday (). Result;) and asynchronously (just call ReserveAHolliday ();) from MAIN (depending on which line you are commenting on). and you can see the effect ("END" is printed before / after the reservation is completed). I prefer to use Task.WhenAll () functions, which are more readable. also note that he preferred to use the Task.Delay (100) function instead of Thread.sleep inside GetNumber1.

  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; } } 
+2
source

Your async should start somewhere, and since your program has a starting point, this is a synchronous method at this point. Most async begin with what we like to call async void , which are mostly methods of fire and forgetting. It starts the task, and it doesn’t matter what it returns. If you need to wait for something in a synchronous way, you can use the .Wait() method for the task or use .Result to get the result of the task.

For your real world, if you want to run both tasks at the same time, you need to do something like this:

 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; } 

I highly recommend watching this video . This gives you a good idea of ​​how Async works, and can get you started in the wonderful world of Async.

+1
source

Thanks FrankerZ for the correct answer! So my litle example should look something like this:

 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; } 

// other methods are ommites, because they are the same as GetNumber1}

0
source

To use the await keyword inside a method, it must be async . It was a design that simplified backward compatibility.

Main cannot be async , because this is the starting point of the program, so you usually need to somehow block the program. You can do this by locking Task or even calling Console.ReadLine .

Tasks usually performed in the background thread and background threads do not support your program if all priority threads are stopped.

I have an introductory blog post on async-await here

0
source

The ReserveAHolliday method cannot be made synchronous if you use the wait keyword in it.

What might be possible is to simply block until both async methods return their value. I do not recommend this because it can lead to deadlocks or other unforeseen errors.

If you don’t have a synchronization context (like a console application), you can simply write

 bool hotelOK = ReserveAHotel().Result; 

But I believe that you ultimately want to create a graphical interface. This is where blocking falls apart. Because the user interface application (Forms and WPF) has context and expects asynchronous methods to cause deadlocks. More here

There are workarounds for this problem, but they are highly dependent on the design of your application.

Edit:

If your library code needs a synchronization context, then locking is likely to cause a deadlock.

If you do not need this, it is possible to use ConfigureAwait(false) in your library code and exit with a lock.

What I recommend: async / await completely or not async / await at all. There are other possibilities to make your code asynchronous, for example: based on events, but, like everything else in life, have their pros and cons.

Read this blog post from Stephen Cleary. He explains why blocking asynchronous code will be inhibited and how you can avoid it.

0
source

All Articles