【问题标题】:Confusion over Asynchronous code and Await .net对异步代码和 Await .net 的困惑
【发布时间】:2020-10-08 18:14:28
【问题描述】:

我确信这个问题以前曾以多种形式被问过,但我正在努力寻找一些东西来澄清我的理解。

据我了解,asynchronously 在 .Net 中运行某些代码部分的概念是基于将工作发送到多个线程,以便它可以与其他工作并行运行。在某些情况下,我们需要等待这项工作完成,然后才能继续下一件事情,而在其他情况下,我们不需要。我主要对如何处理这些差异感到困惑。

我可以使用各种类比,但让我们看看一个建筑商或建筑商团队建造房屋。在不同的阶段,团队正在一起处理不同的任务,或者一起完成一个任务,这里有一个非常简化的演练。

  1. 第一项任务是基础工作。没有什么可做的,所以每个人都必须努力挖掘基础。
  2. 我们需要先完成基础工作,然后才能做其他事情。
  3. 地基工程完成后,我们开始砌块并砌墙。
  4. 现在我们有电工和水管工进来的墙
  5. 他们各自的任务被发送到每个行业团队并并行运行以安装第一次修复布线和管道工作。
  6. 与此同时,有人联系了 Royal Mail 以将此新地址添加到他们的邮政编码/地址数据库中。
  7. 水管工和电工已经完成,我们可以开始石膏板了。 .....等

在这个类比中,我们有Task的三种类型;

  • 必须先完成前两项工作(基础工程和砌块工程),然后才能完成其他任何工作,因此我们在主工作线程中连续运行它们。
  • 电工和水管工是两个单独的线程一起运行,他们不需要互相等待完成,但我们可能需要知道或两者是否已完成。李>
  • 邮政编码数据库对我们的新房子的建造没有影响,所以作为一个建筑商我们对此没有兴趣,我们只是把它送到另一个团队(皇家邮政),他们做他们的事情,我们没有真正需要知道什么时候完成,所以这是一个发送后忘记的任务。

我在 SO 上发现了这个问题:

How to put this function inside a separate thread

很有帮助,主要是“igrimpe”的回复,我复制一下他的代码:

Public Class Form1

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    ' fire and forget:
    Task.Run(Sub() FooA()).ContinueWith(Sub() FooB()).ContinueWith(Sub() FooC())
    Console.WriteLine("Button1 done")

End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

    ' fire and forget:
    Task.Run(Sub()
                 FooA()
                 FooB()
                 FooC()
             End Sub)
    Console.WriteLine("Button2 done")

End Sub

Private Async Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click

    ' wait but dont block:
    Await Task.Run(Sub()
                       FooA()
                       FooB()
                       FooC()
                   End Sub)
    Console.WriteLine("Button3 done")

End Sub

Private Sub FooA()
    Threading.Thread.Sleep(1000)
    Console.WriteLine("A")
End Sub

Private Sub FooB()
    Threading.Thread.Sleep(1000)
    Console.WriteLine("B")
End Sub

Private Sub FooC()
    Threading.Thread.Sleep(1000)
    Console.WriteLine("C")
End Sub

End Class

他说“一劳永逸”,我认为这是我的邮政编码类比,“等待但不要阻塞”是电工和水管工?在他的示例代码中,这些作业将在各自的 CPU 线程上分别运行,我对吗?

有人可以帮助编写明确概述我上面提到的案例的代码,特别是确定单独或多个任务何时完成,无论是一起还是单独完成,并确保我了解如何触发我不需要响应的任务。

另外

这个函数:

Public Async Sub Report(Message As String)
    Task.Run(Sub() Write(Message)  )
End Sub

来自 Visual Studio 的两个警告:

它们似乎相互矛盾,在主要的Sb 声明中它说这将同步运行,但是我声明Task 它说因为没有await,该方法将在之前继续运行任务可能已经完成 - 在这种情况下(即发即弃)我不在乎。在运行之前添加Await 可以修复此警告,但我不清楚这是否真的是一场火灾,现在就忘了?

【问题讨论】:

  • "... 在 .Net 中异步运行某些代码部分的概念是基于将工作发送到多个线程..." - There is no thread
  • 异步不是并发。线程是一个单独的概念。使用单个线程完全有可能实现您所要求的一切。异步只是意味着我们不做阻塞调用。
  • 我建议您阅读 Stephen Cleary 关于此事的整个系列博客文章。
  • 好的,谢谢,我会的。

标签: .net multithreading asp.net-core async-await task


【解决方案1】:

我将尝试使用另一个类比来解释 Sync 和 Async 之间的区别。

我们需要做早餐。 我们的早餐是由以下任务制作的:

  • 煮鸡蛋(2 分钟)
  • 泡茶(1 分钟)
  • 上菜(1 分钟)

每个任务都可以无人值守

同步方法是:

  • 泡茶然后等待(1 分钟)
  • 制作鸡蛋并等待(2 分钟)
  • 上茶等待(1 分钟)
  • 上鸡蛋并等待(1 分钟)

总任务时间 5 分钟

异步方法:

  • 泡茶
  • 制作鸡蛋
  • 等茶(1 分钟)
  • 上茶(1 分钟)
  • (2 分钟过去了,鸡蛋准备好了)上桌(1 分钟)

总任务时间 3 分钟

如果我们需要扩展早餐的数量,我们可以将所有内容乘以所需的早餐数量(无并发)。 或者我们可以增加工作的人数(线程并发)

【讨论】:

    【解决方案2】:

    我只能通过我的 C# 知识来回答这个问题 :D ... 实际上,您的所有情况都是正确的。

    Public Async Sub Report(Message As String)
        Task.Run(Sub() Write(Message)  )
    End Sub
    

    此代码将执行“一劳永逸”的方法。你可以忽略警告。这是设计的。

    我认为您甚至可以在此处删除 Async 关键字。你不想在这里等待任何东西。这可以清除第一个警告。

    如果您像这样更改代码,则执行将是同步的,因为您要等到任务完成才执行:

    Public Async Sub Report(Message As String)
        Await Task.Run(Sub() Write(Message)  )
    End Sub
    

    在等待的任务中只调用 Write(Message) 而不执行它的唯一区别是,您的 GUI 将保持冻结状态,直到 Write 函数完成。

    【讨论】:

    • 我明白了,所以在这个示例情况下,我真的想解雇并忘记,我对它何时完成(或者实际上是否完成!)不感兴趣,所以我应该忽略 VS 警告和坚持Task.Run(Sub() Write(Message) )
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    • 2021-07-26
    相关资源
    最近更新 更多