C# Task 使用 WhenAll 和 WaitAll 需要注意的坑


1.無限等待

我們在使用 WhenAll 和 WaitAll 時,一定得要注意:1.必須添加超時時間,防止無限等待 2.等待的 Task 一定要保證是啟動的。

比如下面這種寫法:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace TaskForWhenAll
{
    class Program
    {
        static void Main(string[] args)
        {
            var taskList = new List<Task>();
            for (int i = 0; i < 5; i++)
            {
                taskList.Add(new Task(() =>
                {
                    Console.WriteLine("Task {0} is finished", Task.CurrentId);
                }));
            }

            // await Task.WhenAny(taskList);
            Task.WaitAll(taskList.ToArray());
            Console.WriteLine("exit");
        }
    }
}

將不會正常運行,會一直無限等待,因為 new Task 這樣創建出來的 Task 不會自動運行,需要手動調用 Task.Start

改造一下代碼:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace TaskForWhenAll
{
    class Program
    {
        static void Main(string[] args)
        {
            var taskList = new List<Task>();
            for (int i = 0; i < 5; i++)
            {
                taskList.Add(Task.Run(() =>
                {
                    Console.WriteLine("Task {0} is finished", Task.CurrentId);
                }));
            }

            // await Task.WhenAny(taskList);
            Task.WaitAll(taskList.ToArray());
            Console.WriteLine("exit");
        }
    }
}

使用 Task.Run 創建的 Task 是會自動運行的

2.沒有期望的等待

我們在創建 Task 時,可能會定義一個異步委托,以便方便在 Task 里面使用 await,例如:

class Program
{
    static async Task Main(string[] args)
    {
        var taskList = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            taskList.Add(Task.Factory.StartNew(async () =>
            {
                await Task.Delay(3000);
                Console.WriteLine("Task {0} is finished", Task.CurrentId);
            }));
        }

        await Task.WhenAny(taskList);
        Console.WriteLine("exit");
    }
}

直接運行會發生什么

直接就退出了,並沒有等待所有任務執行完畢。

我們換成 Task.Run 是可以正常運行的,這是為什么呢?這是因為我們這種寫法,會把 Task Result 包裝一層,我們需要得到期望的結果需要解除包裝 UnWrap,Task.Factory.StartNew和Task.Run區別之一就有Task.Run會自動執行Unwrap操作。

擴展閱讀:https://www.cnblogs.com/Leo_wl/archive/2012/09/21/2696342.html

我們改造一下代碼

taskList.Add(Task.Factory.StartNew(async () =>
                {
                    await Task.Delay(3000);
                    Console.WriteLine("Task {0} is finished", Task.CurrentId);
                }).Unwrap());

就能按照我們期望的去運行


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM