如何实现"true"异步



在回答这个问题时,Stephen Cleary提到了"假"异步和"真"异步。

有一种

更简单的方法来计划线程池的工作:Task.Run。

真正的异步是不可能的,因为你有一个阻塞方法 您必须使用。所以,你所能做的只是一个解决方法 - 假的 异步,又名阻塞线程池线程。

那么,如何实现真正的异步,就像System.Threading.Tasks.Task中的各种方法一样呢? 如果你挖掘得足够深,不是所有"真正的异步"方法都只是阻止其他线程上的操作吗?

如果你挖掘得足够深,不是所有"真正的异步"方法都只是阻止其他线程上的操作吗?

不。真正的异步操作在整个操作中不需要线程,使用线程会限制可伸缩性并损害性能。

虽然大多数真正的异步操作都是 I/O 操作,但这可能会变得过于复杂而难以理解。(如需深入了解,请阅读斯蒂芬·克利里(Stephen Cleary)的《没有线程》(There Is No Thread)。

例如,假设您要await用户的按钮单击。由于存在Button.Click事件,我们可以利用TaskCompletionSource异步等待事件引发:

var tcs = new TaskCompletionSource<bool>();
_button.Click += (sender, EventArgs e) => tcs.SetResult(false);
await tcs.Task;

没有非通用TaskCompletionSource所以我使用具有虚拟值的bool。这将创建一个未连接到线程的Task,它只是一个同步构造,并且仅在用户单击该按钮(通过SetResult)时完成。您可以长时间awaitTask,而不会阻塞任何线程。

Task.Delay的实现方式非常相似,使用在其回调中完成等待任务的System.Threading.Timer

如果你挖掘得足够深,不是所有"真正的异步"方法都只是阻止其他线程上的操作吗?

相反。真正的异步方法一直异步到操作系统级别。默认情况下,这些类型的方法即使在使用 IRP(IO 请求数据包)和 DPC 的设备驱动程序级别也不会阻止。

请参阅如何使用 async/await 在 UI 线程上异步运行多个任务? 我详细介绍了重叠 IO 如何一直向下工作。

那么,如何实现真正的异步,就像System.Threading.Tasks.Task中的各种方法一样呢?

Task表示将来将要完成的工作单元。这与异步 IO 无关。您可能会认为这是因为async-awaitawaitable 很好地协同工作。大多数 BCL 库通过 TaskAwaiter 公开异步 IO 操作,这就是为什么您假设它是实现异步的库。

最新更新