对异步代码和 Await .net 的混淆
Confusion over Asynchronous code and Await .net
我确信这个问题以前曾以多种形式被问过,但我正在努力寻找一些东西来澄清我的理解。
据我所知,asynchronously
运行 在 .Net 中使用某些代码段的概念是基于将工作发送到多个线程,这样它就可以 运行 与其他工作并行。在某些情况下,我们需要等待这项工作完成,然后才能继续进行下一件事,而在其他情况下,我们则不需要。我主要对如何处理这些差异感到困惑。
我可以使用各种类比,但让我们看看建造房屋的建筑商或建筑商团队。在不同的阶段,团队在单独的任务上一起工作,或者在一个任务上一起工作,这是一个非常简化的演练。
- 第一项任务是基础工作。没办法了,大家只好挖地基了。
- 我们需要完成基础工作才能做其他事情。
- 基础工程完成后,我们开始砌块并砌墙。
- 现在我们有了墙,电工和水管工进来了
- 他们各自的任务被发送给每个行业团队,运行 并行安装首次修复布线和管道工程。
- 与此同时,有人联系了皇家邮政,希望将这个新地址添加到他们的 postcode/address 数据库中。
- 水管工和电工已经完成,所以我们可以开始石膏板了。
.....等
在这个类比中,我们有三种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
该方法将在任务可能完成之前继续 运行ning - 在这种情况下(即发即忘)我不关心。在 运行 之前添加 Await
修复了此警告,但我不清楚这是否真的是火灾,现在忘记了吗?
我只能用我的 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 函数完成。
我将尝试使用另一个类比来解释同步和异步之间的区别。
我们需要做早餐。
我们的早餐是由这些任务完成的:
- 煮鸡蛋(2 分钟)
- 泡茶(1 分钟)
- 发球(1 分钟)
每个任务都可以无人值守
同步方法为:
- 泡茶并等待(1 分钟)
- 制作鸡蛋并等待(2 分钟)
- 端茶等待(1 分钟)
- 端上鸡蛋并等待(1 分钟)
总任务时间 5 分钟
异步方法:
- 泡茶
- 制作彩蛋
- 等待喝茶(1 分钟)
- 端茶(1 分钟)
- (经过 2 分钟,鸡蛋准备好)上鸡蛋(1 分钟)
总任务时间 3 分钟
如果我们需要缩放早餐的数量,我们可以将所有内容乘以所需的早餐数量(无并发)。
或者我们可以增加工作人员的数量(线程并发)
我确信这个问题以前曾以多种形式被问过,但我正在努力寻找一些东西来澄清我的理解。
据我所知,asynchronously
运行 在 .Net 中使用某些代码段的概念是基于将工作发送到多个线程,这样它就可以 运行 与其他工作并行。在某些情况下,我们需要等待这项工作完成,然后才能继续进行下一件事,而在其他情况下,我们则不需要。我主要对如何处理这些差异感到困惑。
我可以使用各种类比,但让我们看看建造房屋的建筑商或建筑商团队。在不同的阶段,团队在单独的任务上一起工作,或者在一个任务上一起工作,这是一个非常简化的演练。
- 第一项任务是基础工作。没办法了,大家只好挖地基了。
- 我们需要完成基础工作才能做其他事情。
- 基础工程完成后,我们开始砌块并砌墙。
- 现在我们有了墙,电工和水管工进来了
- 他们各自的任务被发送给每个行业团队,运行 并行安装首次修复布线和管道工程。
- 与此同时,有人联系了皇家邮政,希望将这个新地址添加到他们的 postcode/address 数据库中。
- 水管工和电工已经完成,所以我们可以开始石膏板了。 .....等
在这个类比中,我们有三种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
该方法将在任务可能完成之前继续 运行ning - 在这种情况下(即发即忘)我不关心。在 运行 之前添加 Await
修复了此警告,但我不清楚这是否真的是火灾,现在忘记了吗?
我只能用我的 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 函数完成。
我将尝试使用另一个类比来解释同步和异步之间的区别。
我们需要做早餐。 我们的早餐是由这些任务完成的:
- 煮鸡蛋(2 分钟)
- 泡茶(1 分钟)
- 发球(1 分钟)
每个任务都可以无人值守
同步方法为:
- 泡茶并等待(1 分钟)
- 制作鸡蛋并等待(2 分钟)
- 端茶等待(1 分钟)
- 端上鸡蛋并等待(1 分钟)
总任务时间 5 分钟
异步方法:
- 泡茶
- 制作彩蛋
- 等待喝茶(1 分钟)
- 端茶(1 分钟)
- (经过 2 分钟,鸡蛋准备好)上鸡蛋(1 分钟)
总任务时间 3 分钟
如果我们需要缩放早餐的数量,我们可以将所有内容乘以所需的早餐数量(无并发)。 或者我们可以增加工作人员的数量(线程并发)