使用 Parallel.ForEach 启动两个并行任务

Start two parallel tasks with Parallel.ForEach

在此代码中 Parallel.ForEach 没有等待。经过的秒数立即 returning 0。此代码位于 PCL:

private void Button_Clicked(object sender, EventArgs e)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();

    List<Task> taskList = new List<Task>();
    Task taskA = new Task(ExecuteTaskAAsync);
    Task taskB = new Task(ExecuteTaskBAsync);
    taskList.Add(taskA);
    taskList.Add(taskB);

    Parallel.ForEach(taskList, t => t.Start());

    watch.Stop();
    System.Diagnostics.Debug.WriteLine("Seconds Elapsed: " + watch.Elapsed.Seconds);
}

private async void ExecuteTaskAAsync()
{
    for (int i = 0; i < 10; i++)
    {
        System.Diagnostics.Debug.WriteLine("Task A: [{0}]", i + 1);
        await Task.Delay(1000);
    }

    System.Diagnostics.Debug.WriteLine("Finished Task A!");
}

private async void ExecuteTaskBAsync()
{
    for (int i = 0; i < 10; i++)
    {
        System.Diagnostics.Debug.WriteLine("Task B: [{0}]", i + 1);
        await Task.Delay(1000);
    }

    System.Diagnostics.Debug.WriteLine("Finished Task B!");
}

负责此行为的似乎是 t.Start(),它启动了一个新线程并且 Parallel.ForEach 已经完成。我还通过使用 Task 作为 return 类型和此代码进行了尝试:

Parallel.Invoke(async() => await ExecuteTaskAAsync(), async() => await ExecuteTaskBAsync());

同样,经过的秒数立即 return 变为 0。我怎样才能 运行 两个任务并行?

并行工作正常 - 它正在开始 两个并行任务,正如您的代码所要求的那样。它只是不等待这些任务完成(即使是,这些任务也不会等待您的 async void 方法完成)。

既然你处理的是异步任务,你真正想要的是异步并发,而不是并行并发。它们都是并发(同时做不止一件事),但并行是关于生成多个线程,而异步是关于释放当前线程。

异步并发通过使用 Task.WhenAll 工作,例如:

private async void Button_Clicked(object sender, EventArgs e)
{
  Stopwatch watch = new Stopwatch();
  watch.Start();

  Task taskA = ExecuteTaskAAsync();
  Task taskB = ExecuteTaskBAsync();

  await Task.WhenAll(taskA, taskB);

  watch.Stop();
  System.Diagnostics.Debug.WriteLine("Seconds Elapsed: " + watch.Elapsed.Seconds);
}

private async Task ExecuteTaskAAsync()
{
  for (int i = 0; i < 10; i++)
  {
    System.Diagnostics.Debug.WriteLine("Task A: [{0}]", i + 1);
    await Task.Delay(1000);
  }

  System.Diagnostics.Debug.WriteLine("Finished Task A!");
}

private async Task ExecuteTaskBAsync()
{
  for (int i = 0; i < 10; i++)
  {
    System.Diagnostics.Debug.WriteLine("Task B: [{0}]", i + 1);
    await Task.Delay(1000);
  }

  System.Diagnostics.Debug.WriteLine("Finished Task B!");
}

另请注意,我将现有的 async void 方法更改为 async Task;这是因为 async void 是不自然的,应该只用于事件处理程序。有关详细信息,请参阅我在 async best practices 上的 MSDN 文章。

最后一点,you should never use the Task constructor。我在我的博客上进行了详细解释,但归结为:总是 更好的选择。