C# 中的 async/await 是否比 64 位环境中的线程具有性能优势? [关闭]

问题描述 投票:0回答:1

据我所知,async/await 相对于通过多线程实现并发的好处,如果我的计算是正确的,那么在我看来,这些好处大多只在非常极端的情况下才有意义。我想知道我是否正确理解它是如何工作的,以及 async/await 对使用线程的性能影响。为了设置一些上下文,我在这里主要讨论后端服务和批处理中的并发性,其中许多线程同时执行类似的任务,彼此独立。

所以首先我会解释我认为 async/await 的主要好处是什么,然后我会解释为什么我认为这在大多数情况下不是很相关。

让我们从一个事实开始,当一个线程正在等待输入或事件时,操作系统已经知道切换到另一个线程直到这个输入或事件到达,所以当一个“同步”I/O 操作(例如一个 http call) 阻塞当前线程,它不会阻塞其他线程。从概念上讲,这与在“异步”操作上使用

await
没有什么不同,因为在操作完成之前当前任务不会继续,而其他任务可以。据我所知,async/await 试图解决的主要问题是每个线程为其堆栈占用固定大小的内存,32 位进程为 1MB,64 位进程为 4MB .当物理内存有限且小于使用的虚拟内存时,操作系统开始在内存和磁盘之间交换页面,这成为一个巨大的瓶颈。异步任务不使用线程,因此只使用它们实际需要的内存,从而允许进程在填满物理内存之前运行比线程更多的任务。

AFAIU,在 32 位操作系统中这是一个真正的问题,因为物理内存限制为 4GB。理论上,这允许最多 4,000 个线程并发运行,但实际上大块物理内存已经被操作系统、其他进程和当前进程的堆使用,实际上将线程数量限制在最多几百个。

然而,现在 64 位操作系统和内存非常便宜(无论是物理内存还是云端),例如 64GB 的物理内存,理论上的限制是 16,000 个线程,而操作系统和其他东西仍然占用它们的空间(名义上可能比以前更多),我相信它们的相对大小比 32 位操作系统小得多。我承认没有进行适当的计算或实验,但我猜想使用 64GB 物理内存运行大约 10,000 个线程仍然是现实的,而无需访问磁盘进行页面交换。所以假设我的计算和结论是正确的,如果运行大约 10,000 个并发线程就足够了,那么 async/await 不会给你带来太多性能优势。

那么,我的结论是正确的,还是我遗漏了什么?

PS:如果我没理解错,我上面的计算甚至是悲观的,因为操作系统以4KB的页为单位管理内存,所以如果线程的4MB堆栈中只有一小部分真正被使用,那么只有被使用的页占用物理内存线程和任务之间没有太大区别。在 32 位操作系统中,进程的虚拟内存也被限制为 4GB,无论物理内存如何,都限制了该进程中的线程数,但在 64 位进程中,限制约为 ~4e+12...

c# multithreading memory-management async-await scalability
1个回答
0
投票

据我所知,async/await 相对于通过多线程实现并行性的好处。

不。在服务器应用程序中 async/await 的好处是线程的经济使用,不使用线程 当异步操作正在运行时。在 GUI 应用程序的上下文中,async/await 的好处是在长时间的异步操作期间释放宝贵的 UI 线程,以保持 UI 响应。 术语“并行性”准确使用时意味着在多个处理器/内核上同时运行代码。异步操作通常不在线程上运行,因此在异步上下文中使用的正确术语是“并发”,而不是“并行”。 Async/await 可以用来促进并发,但这不是它的主要目的。您也可以在没有异步的情况下实现并发,通过使用(阻塞)大量线程,并且只需付出增加内存消耗的代价,因为线程需要相当数量的内存(大约 1MB)用于它们的堆栈。

所以你的整个问题都是基于不正确的假设。老实说,我还没有读完第一段。我的建议是修复最初的假设(在这种情况下我会删除这个答案),或者用有意义的假设提出一个新问题。

© www.soinside.com 2019 - 2024. All rights reserved.