阻塞代码在现代系统上真的很贵吗



我正在努力更好地理解异步编程(主要针对C#(和阻塞/非阻塞代码的概念。

在C#中,如果我在Task上调用.Wait(),它总是被认为是"1"吗;阻塞"?我知道当前线程将被阻塞。然而,线被放入";等待";state(AFAIK(,并且AFAIK它永远不会被OS调度,直到任务完成时被唤醒(我假设线程被内核魔术唤醒(

在这种情况下,这种阻塞操作所花费的CPU时间在等待期间应该可以忽略不计。事实确实如此吗?

那么异步编程的优势来自哪里呢?是因为它允许超过1000个线程,而操作系统不允许吗?是因为每个异步任务的内存开销低于线程的开销吗?请记住;事件循环";在异步上下文中管理所有任务的kernerl还需要管理所有异步任务的调度、记账等。这真的比kernerl在阻塞情况下管理线程所需的工作量少吗?

Wait()会像调用非异步I/O一样阻塞线程。

阻塞并不是天生的低效。事实上,如果您的进程只有很少的线程,那么它可能会更具性能。Windows的调度程序实际上为I/O阻塞的线程提供了一些有趣的特殊设计,您可以在《Windows内部构件》一书中了解到这些设计,例如,如果线程在I/O上等待很长时间,则将其提升到行的前面。

然而,它没有规模。你创建的每个线程都有开销:堆栈和寄存器空间的内存,应用程序和.NET内部使用的线程本地存储,所需额外内存导致的缓存抖动,上下文切换等等。这通常不会有效地使用资源,尤其是当每个线程的大部分时间都会被阻塞时。

Async利用了这样一个事实,即从概念上讲,我们并不真正需要线程所提供的一切——我们只需要并发性,这样我们就可以在如何使用资源方面进行更多与领域相关的优化。

默认情况下异步对项目几乎没有影响。如果你的应用程序不需要为可扩展性进行超优化,它不会对你造成伤害或帮助。如果你的应用程序做到了,那么它将是一个巨大的帮助。像async/await这样的东西可以帮助您更好地对并发进行建模,因此无论您的perf目标如何,它都是有用的。

异步I/O正朝着一个更凉爽的地方发展:像Windows RIO和Linux的io_uring这样的I/O API允许您在不切换上下文的情况下进行I/O。目前,.NET并没有利用这些优势,但PipeWriterPipeReader是为未来而构建的。

最新更新