簡體   English   中英

當動作未知時如何等待 Task.Run(action)

[英]How to Await Task.Run(action) when action is unknown

我有以下代碼:

  static void Main(string[] args)
    {
        Run(() => LongProcess()).ContinueWith( t => Run(() => LongerProcess()));

        int count = 5;
        do
        {
            Console.WriteLine(count.ToString());
            Thread.Sleep(100);
            count++;
        } while (count < 20);

        Console.ReadKey();
    }

    private static void LongProcess()
    {

        Console.WriteLine("Long Process 1");
        Thread.Sleep(2000);
        Console.WriteLine("Long Process 2");
    }

    private static void LongerProcess()
    {
        Console.WriteLine("Longer Process 1");
        Thread.Sleep(3000);
        Console.WriteLine("Longer Process 2");
    }

    private static async Task Run(Action action)
    {

        await Task.Run(action);  //shouldn't this wait until the action is completed??
                                // how should I modify the code so that the program waits until action is done before returning?

    }

使用await Task.Run(action); ,我期待該程序將等到任何action完成,然后再進行下一步。 換句話說,我期待輸出如下:

Long Process 1
Long Process 2
Longer Process 1
Longer Process 2
5
6
7
8
...
19

但是,輸出就像

Long Process 1
5
6
7
8
...
19
Long Process 2
Longer Process 1
Longer Process 2

問題:

  1. 為什么不await Task.Run等待action完成?
  2. 如何更改代碼以提供我想要的輸出?

使用await不等待,這就是重點。 如果您想等待,請使用Task.Wait

但是, async方法的執行只會在等待的任務完成后(它是一個延續)才會恢復。 讓我們看看你的async方法:

private static async Task Run(Action action)
{

    await Task.Run(action);
    // There is nothing here
}

任務完成后沒有代碼要執行……好吧, async方法返回一個完成時完成的任務。 讓我們看看你是否在await ……

Run(() => LongProcess()).ContinueWith( t => Run(() => LongerProcess()));

你沒有。 您啟動該任務並忘記它。


我認為這就是你想要的:

static async void Main(string[] args)
{
    await Run(() => LongProcess());
    await Run(() => LongerProcess());

    int count = 5;
    do
    {
        Console.WriteLine(count.ToString());
        Thread.Sleep(100);
        count++;
    } while (count < 20);

    Console.ReadKey();
}

注意:Async Main 是 C# 7.1 的一項功能。

此代碼將運行調用LongProcess的任務,然后作為延續運行LongerProcess的任務,然后作為延續代碼的其余部分。

為什么你想要它而不是同步調用這些方法是我無法理解的。

順便說一下,在async方法中,您可以使用await Task.Delay(milliseconds)而不是Thread.Sleep(milliseconds) 優點是線程不等待。 這就像在單個執行計時器上進行延續。


如果async/await只是延續,您可能想知道為什么人們想要使用它們而不是ContinueWith

讓我給你幾個理由:

  • 帶有async/await代碼更容易閱讀。 減少了使代碼蒙上陰影的嵌套內容。 您可以獨立於理解線程來理解代碼的作用。
  • 帶有async/await代碼更容易編寫。 你只是把它寫成好像它都是同步的,有一些asyncawait在那里閃閃發光。 您可以編寫同步代碼,然后擔心如何使其並發。 您最終也會寫得更少,這意味着您的工作效率更高。
  • 帶有async/await代碼更智能™。 編譯器將您的代碼重寫為連續狀態機,允許您將await放入語句中,而無需任何代碼體操™。 這擴展到異常處理。 你看,在你的即發即棄的任務繼續中,你沒有處理異常。 如果LongerProcess拋出怎么辦? 好吧,使用async/await您可以將await放在try ... catch ,它會做正確的事情™。

這都是很好的關注點分離。


您可能還想知道在什么情況下使用async/await代替同步代碼是個好主意。 答案是它在處理 I/O 操作時大放異彩。 在與外部系統交互時,通常不會立即得到響應。 例如,如果要從磁盤讀取或從網絡下載。

事實上,如果您認為操作表單和處理其事件是 I/O 綁定操作(因為它們是)。 你會發現它們是使用async/await的好地方。 特別是考慮到 UI 線程的同步上下文默認情況下將在同一線程上保持延續。 當然,您可以使用Task.Runasync/await與 CPU 綁定操作一起使用。 什么時候是個好主意? 啊,是的,當您想保持 UI 響應時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM