任务层次结构示例未按预期工作

本文关键字:工作 层次结构 任务 | 更新日期: 2023-09-27 18:34:09

我开始使用C#中的任务。我正在尝试执行此代码。

    private static void CreateSubtask() {
        Task<Int32[]> parent = Task.Run(() =>
        {
            var results = new Int32[3];
            new Task(() => results[0] = 0,
                TaskCreationOptions.AttachedToParent).Start();
            new Task(() => results[1] = 1,
                TaskCreationOptions.AttachedToParent).Start();
            new Task(() => results[2] = 2,
                TaskCreationOptions.AttachedToParent).Start();
            return results;
        });
        var finalTask = parent.ContinueWith(
           parentTask =>
           {
               foreach (int i in parentTask.Result)
                   Console.WriteLine(i);
           });
        finalTask.Wait();
    }

finalTask仅在父Task完成后运行,父Task在所有三个子级完成后完成。您可以使用它来创建非常复杂的Task层次结构,这些层次结构将完成您指定的所有步骤。

相反,我从执行中得到的是三行字:

0
0
0

我期待他们是

0
1
2

我说的对吗?

任务层次结构示例未按预期工作

Task.Run与父任务一起使用会抑制AttachedToParent对子任务的影响:

Task.Run vs Task.Factory.StartNew by Stephen Toub.

请改用Task.Factory.StartNew

问题是您的parent任务在完成启动其他三个任务时完成,而不是在其他三个任务完成时完成。

相反,您可以使用Task.WhenAll创建一个任务,该任务将在所有其他任务本身完成时完成。

使程序更惯用的任务代码的另一个更改是让每个内部任务返回自己的值,而不是改变某些共享状态,这仅仅是因为在多线程环境中处理共享状态可能更难推理。

var parent = Task.WhenAll(Task.Run(() => 0),
    Task.Run(() => 1),
    Task.Run(() => 2));
var finalTask = parent.ContinueWith(t =>
    {
        foreach (int n in t.Result)
            Console.WriteLine(n);
    });
finalTask.Wait();

您只是在开始三个子任务,而不是等待它们完成。像这样调整它,例如:

            var task1 = new Task(() => results[0] = 0,
                TaskCreationOptions.AttachedToParent);
            var task2 = new Task(() => results[1] = 1,
                TaskCreationOptions.AttachedToParent);
            var task3 = new Task(() => results[2] = 2,
                TaskCreationOptions.AttachedToParent);
            task1.Start();
            task2.Start();
            task3.Start();
            task1.Wait();
            task2.Wait();
            task3.Wait();

另请注意,使用您当前的代码,仍然可以显示0 1 2(顺便说一下,不是1 2 3),因为它无法确定子任务何时运行/完成。这可能还取决于您的构建配置(调试/发布)。