首页 > 解决方案 > ThreadPoolTask​​Scheduler internals - Task.WaitAll() 的参数顺序会改变执行顺序吗?

问题描述

我在工作中遇到过类似以下的案例。(为了这个线程的目的,我稍微简化了一点)

这是代码(.net 核心控制台应用程序):

class Program
{
    static void Main(string[] args)
    {
        const int numberOfTasks = 15;
        var taskArray = new Task[numberOfTasks];

        for (int i = 0; i < numberOfTasks; i++)
        {
            var temp = i;
            taskArray[i] = Task.Run(() => SingleTest(temp));
        }

        Task.WaitAll(taskArray);
        Console.WriteLine("FINISHED!!!");

        Console.ReadKey();
    }

    static void SingleTest(int temp)
    {
        var signal = new AutoResetEvent(false);
        var t1 = Task.Run(() =>
        {
            Console.WriteLine($"{temp} T1 started");
            signal.Set();
            Console.WriteLine($"{temp} T1 finished");
        });

        var t2 = Task.Run(() =>
        {
            Console.WriteLine($"{temp} T2 started");
            signal.WaitOne();
            Console.WriteLine($"{temp} T2 finished");
        });

        Task.WaitAll(t1, t2);
        //Task.WaitAll(t2, t1);
        Console.WriteLine($"{temp}: Both tasks finished");
    }
}

当我使用 8 次或更多循环迭代运行此代码时,在所有 T2 任务启动之前,没有一个 T1 任务启动,这看起来很奇怪。我的问题是为什么会发生这种情况?我本来希望这些任务以完全随机的顺序开始。

这是示例执行的输出开始(8 次迭代):

5 T2 started
7 T2 started
3 T2 started
0 T2 started
4 T2 started
6 T2 started
2 T2 started
1 T2 started
1 T1 started
1 T1 finished
1 T2 finished
1: Both tasks finished
...

当我更改 Task.WaitAll() 调用中的参数顺序时(如注释掉的行),行为完全不同,其中任务以(看似)随机顺序启动(大多数 T1 任务似乎开始早于它们的 T2 等效项,但是在所有 T1 任务完成之前至少启动了一些 T2 任务)

样本输出:

7 T1 started
5 T1 started
5 T1 finished
4 T1 started
4 T1 finished
1 T1 started
1 T1 finished
6 T1 started
6 T1 finished
3 T1 started
3 T1 finished
1 T2 started --For example,this T2 task was started before some of the T1 tasks
0 T1 started
0 T1 finished
2 T1 started
2 T1 finished
4 T2 started
4 T2 finished
3 T2 started
1 T2 finished
7 T1 finished
0 T2 started
0 T2 finished
2 T2 started
6 T2 started
6 T2 finished
3 T2 finished
1: Both tasks finished

所以,我想知道的是,在创造这种行为的幕后发生了什么?

标签: c#.nettasktask-parallel-librarythreadpool

解决方案


推荐阅读