简体   繁体   English

在 C# 完成另一个异步方法后调用异步方法

[英]Call async method after another async method is finished in C#

I want to call step2 method after step 1 is finished.我想在步骤 1 完成后调用 step2 方法。 With this code below the methods step 1 and step 2 are executing in parallel.使用下面的代码,方法步骤 1 和步骤 2 并行执行。 And of course I they need to be asynchronous so they won't block step 3 from executing.当然,我需要它们是异步的,这样它们就不会阻止第 3 步的执行。

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#!请记住,我是 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.最后设置 step3() 的地方将首先执行,因为没有延迟,而且 step2() 必须等待 step1() 完成。

Is this at all possible with async/await in C#. I think this can be done with promises in javascript.这完全有可能在 C# 中使用异步/等待。我认为这可以通过 javascript 中的承诺来完成。

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.如果您将Main方法(以及step1step2 )更改为async Task而不是void (或async void ),您将能够等待您的方法。

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 .我建议您查看这篇 Microsoft 文章,以更好地了解async Taskasync void

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.await作用于未完成的Task时,奇迹就会发生。 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 ).此时,该方法向调用方法返回一个新的不完整Task (或者如果它是void返回任何内容,这就是为什么您应该避免使用async void )。

So if you call step1() first, then step1() will start executing first - there is no way around that.因此,如果您首先调用step1() ,那么step1()将首先开始执行 - 没有办法解决这个问题。 But when step1() hits await Task.Run(...) then it returns and the Main method continues executing.但是当step1()命中await Task.Run(...)时,它返回并且Main方法继续执行。 At that point, you can decide what to do.到那时,您可以决定要做什么。 Do you want to wait until step1() completes or go do something else?你想等到step1()完成还是 go 做其他事情?

Here is what the code would look like if you want:如果需要,代码如下所示:

  1. step1() to start executing first. step1()首先开始执行。
  2. step2() to only start after step1() completes. step2()仅在step1()完成后才开始。
  3. step3() executes as soon as possible after step1() starts, but without waiting for step1() to complete. step3()step1()开始后尽快执行,但不等待step1()完成。
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: output 是:

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.如果您希望step3()step1()甚至开始执行之前执行,那么您需要先调用step3() - 没有办法绕过它。

If the constraints are如果约束是

  1. step2 should start when step1 ends step2应该在step1结束时开始
  2. step1 and step2 should not block step3 step1 和 step2 不应阻塞 step3
  3. Calling code must be (eg no ContinueWith)调用代码必须是(例如没有 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.除非您可以控制步骤中的代码,并执行线程信号以防止步骤 2 在步骤 1 结束之前开始。 Read about ManualResetEvent.阅读有关 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();
}

Drop the async, it is not meaning what you think.放弃异步,这不是你想的那样。 Use ContinueWith使用 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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM