【问题标题】:2 Async tasks in parallel and waiting for results - .Net2 并行异步任务并等待结果 - .Net
【发布时间】:2015-10-06 06:58:58
【问题描述】:

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

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

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

我将它们运行为:

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,然后完成了任务 2。我已将迭代次数增加到接近正无穷,并进行了检查 - 情况相同。

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

【问题讨论】:

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


    【解决方案1】:

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

    支持文档:link

    async 方法通常包含一个或多个 await 运算符,但没有 await 表达式不会导致编译器错误。 如果 async 方法不使用 await 运算符来标记暂停点,则该方法会像同步方法一样执行,尽管有 async 修饰符。编译器会针对此类方法发出警告。

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

    警告此异步方法缺少“等待”运算符,因此将同步运行。考虑使用“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 方法执行足够的工作以使并行化变得引人注目。

    【讨论】:

    • 完美,谢谢。是的,我错过了Run 位。谢谢指出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多