簡體   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