繁体   English   中英

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

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

我想在步骤 1 完成后调用 step2 方法。 使用下面的代码,方法步骤 1 和步骤 2 并行执行。 当然,我需要它们是异步的,这样它们就不会阻止第 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();
        }
    }
}

任何帮助将不胜感激。 请记住,我是 C# 的初学者!

编辑:

  1. 我知道即使使用这段代码我也可以获得最终结果。

     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();

即使根本没有异步/等待。

  1. 这个问题的重点是做一个小的概念验证应用程序,即使代码是这样设置的:

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

最后设置 step3() 的地方将首先执行,因为没有延迟,而且 step2() 必须等待 step1() 完成。

这完全有可能在 C# 中使用异步/等待。我认为这可以通过 javascript 中的承诺来完成。

如果您将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();
}

我建议您查看这篇 Microsoft 文章,以更好地了解async Taskasync void

对于异步方法的工作原理可能存在误解。 所有异步方法开始同步运行,就像任何其他方法一样。 await作用于未完成的Task时,奇迹就会发生。 此时,该方法向调用方法返回一个新的不完整Task (或者如果它是void返回任何内容,这就是为什么您应该避免使用async void )。

因此,如果您首先调用step1() ,那么step1()将首先开始执行 - 没有办法解决这个问题。 但是当step1()命中await Task.Run(...)时,它返回并且Main方法继续执行。 到那时,您可以决定要做什么。 你想等到step1()完成还是 go 做其他事情?

如果需要,代码如下所示:

  1. step1()首先开始执行。
  2. step2()仅在step1()完成后才开始。
  3. 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();
}

output 是:

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

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

如果约束是

  1. step2应该在step1结束时开始
  2. step1 和 step2 不应阻塞 step3
  3. 调用代码必须是(例如没有 ContinueWith)

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

那么答案是这是不可能的。

除非您可以控制步骤中的代码,并执行线程信号以防止步骤 2 在步骤 1 结束之前开始。 阅读有关 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();
}

放弃异步,这不是你想的那样。 使用 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