2并行异步任务并等待结果 - .Net

时间:2015-07-16 17:31:07

标签: .net asynchronous parallel-processing async-await task-parallel-library

我打算并行运行两个任务并等待它们完成。这是我的两个任务:

Dim task1 As Task = tempWorker1()
Dim task2 As Task = tempWorker2()
Await Task.WhenAll(task1, task2).ConfigureAwait(False)

我将它们视为:

From 1:1000
From 1:2000
From 1:3000
From 1:4000
From 1:5000
From 2:1000
From 2:2000
From 2:3000
From 2:4000
From 2:5000

但是,我不认为这些任务是并行运行的。

以下是我得到的输出:

{{1}}

如您所见,它完成任务1,然后任务2完成。我已将迭代次数增加到接近正无穷大并检查 - 这是相同的故事。

我们如何并行运行这两项任务?

1 个答案:

答案 0 :(得分:1)

将方法标记为Async仅意味着现在允许方法在方法中的一个或多个异步操作上Await。但关键字本身并没有神奇地将方法转变为异步方法。事实上,因为您没有等待tempWorker1tempWorker2方法中的任何内容,所以您的方法实际上是同步的。

支持文档:link

  

异步方法通常包含一个或多个await运算符,但缺少await表达式不会导致编译器错误。 如果异步方法不使用await运算符来标记挂起点,则该方法将作为同步方法执行,尽管存在异步修饰符。编译器会对此类方法发出警告。

因为使用Async关键字标记方法而不等待方法中的任何内容是没有用的,编译器应该给出以下警告:

  

警告此异步方法缺少“Await”运算符,因此将同步运行。考虑使用'Await'运算符等待非阻塞API调用,或'Await Task.Run(...)'在后台线程上执行CPU绑定工作。

在这种情况下,如果要并行化工作,则需要在单独的线程中启动它们。一种方法是通过调用Task.Run。请注意,通过使用Task.Run,您的2种方法实际上不再需要设置Async关键字,甚至不需要保留此功能。

所以你可以像这样完成你的目标:

   Private Sub tempWorker1()
      For i = 1 To 5000
         If i Mod 100 = 0 Then
            Console.WriteLine("From 1:{0}", i)
         End If
      Next
   End Sub

   Private Sub tempWorker2()
      For i = 1 To 5000
         If i Mod 100 = 0 Then
            Console.WriteLine("From 2:{0}", i)
         End If
      Next
   End Sub

然后你像这样并行执行工作:

  Dim task1 As Task = Task.Run(AddressOf tempWorker1)
  Dim task2 As Task = Task.Run(AddressOf tempWorker2)
  Await Task.WhenAll(task1, task2).ConfigureAwait(False)

注意 :即使编码正确,如果每个tempWorkerX方法执行的工作不是太多,您也可能无法看到并行执行大。如果完整方法的执行能够在单个时间片或量子内执行,则它可能仍然看起来好像一个方法执行并在另一个方法开始之前完成。确保您的tempWorkerX方法执行足够的工作以使并行化变得明显。