【问题标题】:execute pair of tasks in Parallel并行执行一对任务
【发布时间】:2016-09-17 10:20:20
【问题描述】:

有两个执行 On/Off 的任务,我想创建这些(对)的列表并并行执行它们。含义:每个Task都封装了TaskA和TaskB——TaskB总是等待TaskA先完成。所以我应该以并行执行TaskA/TaskB的“集合”来结束

任务 = {TaskA, TaskB} , {TaskA, TaskB}, {TaskA, TaskB} : 并行执行这 3 组任务

    private static async Task TaskA()
    {
        await Task.Delay(2000);
        Console.WriteLine("ended TaskA");
    }

    private static async Task TaskB()
    {
        await Task.Delay(2000);
        Console.WriteLine("ended TaskB");
    }

    static void StartTask()
    {
        Task.Run(() =>
        {
            TaskA().Wait();
            TaskB().Wait();
        });
    }

主要:

        List<Task> tasks = new List<Task>();
        int taskCount = 3;

        for (var i = 0; i < taskCount; i++)
        {
            var task = new Task(StartTask);
            tasks.Add(task);
        }

        Parallel.ForEach(tasks, task => task.Start());

目前我得到这个:

ended TaskA
ended TaskA
ended TaskA
ended TaskB
ended TaskB
ended TaskB

我相信输出应该是:

ended TaskA
ended TaskB
ended TaskA
ended TaskB
// etc..

另外,试过这个,但仍然是同样的问题:

static void StartTask()
{
    Task task = TaskA().ContinueWith(x => TaskB().Wait(), TaskContinuationOptions.OnlyOnRanToCompletion);
}

编辑 1:

    Parallel.For(1, taskCount, (i, state) =>
    {
        TaskA().ContinueWith(x => TaskB().Wait(), TaskContinuationOptions.OnlyOnRanToCompletion);
    });

【问题讨论】:

  • 为什么不直接从 taska 的末尾运行 taskb?
  • 虽然我就是这么做的
  • 私有静态异步任务 TaskA() { await Task.Delay(2000); Console.WriteLine("结束 TaskA");TaskB(); }
  • 我无法修改 TaskA 或 TaskB。 TaskA 必须在 TaskB 开始之前完成
  • 但是顺便说一下,当前的输出没有问题。因为你并行运行集合,A1、A2、A3 并行启动,当 A1 完成时,A2 和 A3 很可能也同时完成,那么你会看到 B1、B2 和 B3 并行启动。

标签: c# asp.net .net task-parallel-library


【解决方案1】:

我相信输出应该是:...

不,这不是“平行”的意思。如果您要开始三对,那么我希望您已经看到了输出。

也就是说,代码中有几处没有意义。首先,区分“并行”(多线程)和“并发”(同时做多个事情)。看起来你的任务自然是异步的,所以让我们使用异步编程而不是线程来重写:

  • Wait 替换为await
  • 摆脱Task.Run

TaskATaskB 组合成一个新的“配对任务”更容易:

static async Task PairTaskAsync()
{
  await TaskA();
  await TaskB();
}

现在您只想同时运行其中的 3 个“配对任务”。旧代码使用任务构造函数,然后并行化启动任务——这几乎是完全错误的,即使我们想要进行并行化。我们没有;我们想要异步并发。

异步并发通常用Task.WhenAll实现:

List<Task> tasks = new List<Task>();
int taskCount = 3;

for (var i = 0; i < taskCount; i++)
  tasks.Add(PairTaskAsync());

await Task.WhenAll(tasks);

或者,为了最简洁:

await Task.WhenAll(Enumerable.Range(0, 3).Select(_ => PairTaskAsync()));

【讨论】:

  • Stephen,您能否将 cmets 添加到您的代码中以使其更清晰? PairTaskAsync 什么时候开始?当你添加?还是在等待线?
  • 另外,我可以把秒表放在哪里?想知道 TaskA 和 TaskB 在一个对中的完成需要多长时间?
  • 有没有一本书可以简单明了地解释异步/并发/并行?
  • @BobSwanson:TAP pattern 声明任务返回“热” - 也就是说,PairTaskAsync 在您调用它时启动。你可以在PairTaskAsync里面放一个秒表来测量A和B。我有一个book that covers both asynchrony and parallelism
猜你喜欢
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-18
相关资源
最近更新 更多