0

I am learning async methods in C#, and I am trying to create a small program that calls few methods in sequence with a small delay. at the end of the operation, I am calculating the total time elapsed. Here is my code.

public static async Task<string> MakeCoffeeAsync() { Thread.Sleep(3000); return("Coffee is Ready"); } public static async Task<string> ToastBreadAsync() { Thread.Sleep(2000); return ("Bread is Toasted"); } public static async Task<string> ApplyJamToBreadAsync() { Thread.Sleep(1000); return ("Jam added to Bread"); } public static async void MakeBreakfast() { Console.WriteLine("Making Breakfast async way"); Stopwatch sw = new Stopwatch(); sw.Start(); Console.WriteLine(await MakeCoffeeAsync()); Console.WriteLine(await ToastBreadAsync()); Console.WriteLine(await ApplyJamToBreadAsync()); sw.Stop(); Console.WriteLine("Normal Way - Total Time Taken " + sw.ElapsedMilliseconds / 1000 + " Seconds"); } 

This is working correctly and I am getting 6 Seconds as output which is correct.

Now I want two tasks to start simultaneously. One Task can start making the coffee (This will take 3 seconds), and second task will Start the Toast (This will take 2 seconds) and Once the toast is ready, the second task will apply Jam to the already toasted bread (This will take 1 second). The sequence is important for Toast. The Jam should only be applied after the Toast is ready.

Expected output : Total elapsed time should be 3 seconds. Because coffee and (Toast + Jam) will run parallelly.

This is what I have tried.

 public static async void MakeBreakfastConcurrent() { Console.WriteLine("Making Breakfast Concurrent way"); Stopwatch sw = new Stopwatch(); sw.Start(); await Task.Run(() => Console.WriteLine(MakeCoffeeAsync())); await Task.Run(() => { Console.WriteLine(ToastBreadAsync()); Console.WriteLine(ApplyJamToBreadAsync()); }); sw.Stop(); Console.WriteLine("Normal Way - Total Time Taken " + sw.ElapsedMilliseconds / 1000 + " Seconds"); } 

But this is not working as expected. When I run this, nothing prints after "Making Breakfast Concurrent way"

What am I doing wrong, and how to achieve the correct execution order in concurrent way? (probably something like .then() in JS ?)

6
  • 1
    Thread.Sleep does not do what you think it does. (Anyway, generally speaking, no-one should be using Thread.Sleep anyway). Commented Aug 5, 2024 at 6:29
  • You should use await Task.Delay() instead of Thread.Sleep() Commented Aug 5, 2024 at 6:31
  • I can use Task.Delay, just need to simulate a long running method, thats all Commented Aug 5, 2024 at 6:31
  • 1. async/await does not imply concurrency at all - instead, async/await is an alternative syntax for defining a continuation state-machine - everything else (concurrency, threading, synchronization, etc) is a runtime concern (e.g. using the Thread Pool, or using a custom scheduler, etc. 2. Thread.Sleep blocks a thread entirely which defeats the point of using await because the thread itself is blocked and so can't await itself. Commented Aug 5, 2024 at 6:32
  • @Bluemarble Thread.Sleep simulates a blocking call, whereas async/await (and Task-returning asynchronous APIs in general in .NET) are intended for non-blocking calls. There is no reason to (and plenty of reasons against) using async/await with calls to blocking methods (i.e. blocking calls). Commented Aug 5, 2024 at 6:33

2 Answers 2

5

First of all

public static async Task<string> MakeCoffeeAsync() { Thread.Sleep(3000); return("Coffee is Ready"); } 

The method does not do anything asynchronous, so should not be async, nor returning a task. Or you could use Task.Delay instead of Task.Sleep, and remove the Task.Run.

Second problem

public static async void MakeBreakfast() 

The method does not return a task, so there is no way for the caller to know when the method is done. If this is a simple test program it will likely exit before making the complete breakfast. With the exception of event handlers, async methods should just about always return tasks, and all tasks should be awaited, or at least handled somehow. This includes your main method:

static async Task<int> Main(string[] args) { } 

That should ensure your program completes before it exists.

Sign up to request clarification or add additional context in comments.

Comments

0

Your methods are not asynchronous. You should have gotten a compiler warning. A method is only asynchronous, if at least one of its statements contains the await keyword. The async keyword in your method delcaration alone doesn't make your method asynchronous! To make your methods asynchronous, replace Thread.Sleep by await Task.Delay:

public static async Task<string> MakeCoffeeAsync() { await Task.Delay(3000); return("Coffee is Ready"); } public static async Task<string> ToastBreadAsync() { await Task.Delay(2000); return ("Bread is Toasted"); } public static async Task<string> ApplyJamToBreadAsync() { await Task.Delay(1000); return ("Jam added to Bread"); } 

To run your methods concurrently, first call the methods without awaiting them. Then await all tasks and print the results:

Task<string> coffeTask = MakeCoffeeAsync(); Task<string> breadTask = ToastBreadAsync(); Task<string> jamTask = ApplyJamToBreadAsync(); await Task.WhenAll(coffeeTask, breadTask, jamTask); string coffeeResult = await coffeTask; string breadResult = await breadTask; string jamResult = await jamTask; Console.WriteLine(coffeeResult); Console.WriteLine(breadResult ); Console.WriteLine(jamResult ); 

Online-demo: https://dotnetfiddle.net/vhJLtk

3 Comments

Thanks, Tried this, but this too does not print anything. The program ends normally,, the console.writeline statements do not execute.
If you click the link to dotnet-fiddle, you will see that it actually prints something. Do you have an async main method?
Yes working now! The main method was not async. my bad.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.