Home > other >  Call async method after another async method is finished in C#
Call async method after another async method is finished in C#

Time:12-10

I want to call step2 method after step 1 is finished. With this code below the methods step 1 and step 2 are executing in parallel. And of course I they need to be asynchronous so they won't block step 3 from executing.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace test
{
    internal class Program
    {
        static void Main(string[] args)
        {

            async void step1()
            {
                await Task.Run(() =>
                {
                    Thread.Sleep(2000);
                    Console.WriteLine("step 1");
                });

            }

            async void step2()
            {
                await Task.Run(() =>
                {
                    Thread.Sleep(5000);
                    Console.WriteLine("step 2");
                });

            }

            void step3()
            {
                Console.WriteLine("step 3");
            }

            step1();
            step2();
            step3();
            
            // the code below is not working but just and idea 
            // what I want to make. If it at all posible
            // step1().step2()
            // step3() 

            Console.ReadLine();
        }
    }
}

Any help would be greatly appreciated. Keep in mind I am beginner in C#!

Edit:

  1. I know that I can get the end result even with this code.

             void step1()
             {
                 Thread.Sleep(2000);
                 Console.WriteLine("step 1");
             }
             void step2()
             {
                 Thread.Sleep(5000);
                 Console.WriteLine("step 2");
             }
             void step3()
             {
                 Console.WriteLine("step 3");
             }
             step3();
             step1();
             step2();
    

even without async/await at all.

  1. The point of this question is to make small proof of concept application where even though the code is set up like this:

             step1();
             step2();
             step3();
    

where step3() is set last will execute first because has no delay and also step2() will have to wait for step1() to finish.

Is this at all possible with async/await in C#. I think this can be done with promises in javascript.

CodePudding user response:

There may be a misunderstanding about how asynchronous methods work. All async methods start running synchronously, just like any other method. The magic happens when await acts on a Task that is incomplete. At that point, the method returns a new incomplete Task to the calling method (or returns nothing if it's void, which is why you should avoid async void).

So if you call step1() first, then step1() will start executing first - there is no way around that. But when step1() hits await Task.Run(...) then it returns and the Main method continues executing. At that point, you can decide what to do. Do you want to wait until step1() completes or go do something else?

Here is what the code would look like if you want:

  1. step1() to start executing first.
  2. step2() to only start after step1() completes.
  3. step3() executes as soon as possible after step1() starts, but without waiting for step1() to complete.
static async Task Main(string[] args)
{
    async Task step1()
    {
        Console.WriteLine("step 1 starting");
        await Task.Run(() =>
        {
            Thread.Sleep(2000);
            Console.WriteLine("step 1 done");
        });
    }

    async Task step2()
    {
        Console.WriteLine("step 2 starting");
        await Task.Run(() =>
        {
            Thread.Sleep(5000);
            Console.WriteLine("step 2 done");
        });
    }

    void step3()
    {
        Console.WriteLine("step 3");
    }

    var step1task = step1();
    step3();
    await step1task;
    await step2();

    Console.ReadLine();
}

The output is:

step 1 starting
step 3
step 1 done
step 2 starting
step 2 done

If you want step3() to execute before step1() even starts executing, then you need to call step3() first - no way around it.

CodePudding user response:

If you change your Main method (as well as step1 and step2) to async Task instead of void (or async void), you'll be able to await your methods.

static async Task Main(string[] args)
{
    async Task step1()
    {
        await Task.Run(() =>
        {
            Thread.Sleep(2000);
            Console.WriteLine("step 1");
        });

    }

    async Task step2()
    {
        await Task.Run(() =>
        {
            Thread.Sleep(5000);
            Console.WriteLine("step 2");
        });

    }

    void step3()
    {
        Console.WriteLine("step 3");
    }

    step3(); // You can put step3 here if you want it to run before step1 and step2.
    await step1();
    await step2();
    

    Console.ReadLine();
}

I suggest you check this Microsoft article to get a better understanding of async Task vs async void.

CodePudding user response:

If the constraints are

  1. step2 should start when step1 ends
  2. step1 and step2 should not block step3
  3. Calling code must be (e.g. no ContinueWith)

step1();
step2();
step3();

Then the answer is this is not possible.

Unless you have control of the code inside the steps, and do thread signalling to prevent step2 to start before step1 ends. Read about ManualResetEvent.

static void Main(string[] args)
{
    var mre = new ManualResetEvent(false);

    void step1()
    {
        Task.Run(() =>
        {
            Thread.Sleep(1000);
            Console.WriteLine("step 1");
            mre.Set();
        });
    }
    void step2()
    {
        Task.Run(() =>
        {
            mre.WaitOne();
            Console.WriteLine("step 2");
        });
    }
    void step3()
    {
        Console.WriteLine("step 3");
    }

    step1();
    step2();
    step3();

    Console.ReadLine();
}

CodePudding user response:

Drop the async, it is not meaning what you think. Use ContinueWith

    Task step1()
    {
        return Task.Run(() =>
        {
            Thread.Sleep(2000);
            Console.WriteLine("step 1");
        });
    }

    Task step2()
    {
        return Task.Run(() =>
        {
            Thread.Sleep(5000);
            Console.WriteLine("step 2");
        });
    }

    void step3()
    {
        Console.WriteLine("step 3");
    }

    var task = step1()
        .ContinueWith(x => step2());
    step3();
    task.Wait();
  • Related