我知道异步等待是如何工作的。我知道当执行到达等待时,它释放线程并在IO完成后,它从线程池中获取线程并运行剩余的代码。这样就可以有效地利用线程。但我在一些用例中感到困惑:
答案 0 :(得分:29)
我知道异步等待是如何工作的。
你不是。
我知道当执行到达等待时,它会释放线程
没有。当执行到达等待时,将评估等待的操作数,然后检查操作是否完成。如果不是,那么方法的其余部分将作为等待的继续进行注册,并且表示当前方法的工作的任务将返回给调用者。
这些都不是"释放线程"。而是,控制返回到调用者,并且调用者继续在当前线程上执行。当然,如果当前调用者是这个线程上的唯一东西,那么线程就完成了。但是并不要求异步方法是线程上的唯一调用!
IO完成后
等待的不必是IO操作,但我们假设它是。
从线程池中获取线程并运行剩余的代码。
没有。它安排剩余的代码在正确的上下文上运行。该上下文可能是一个线程池线程。它可能是UI线程。它可能是当前的线程。它可能是任何数量的东西。
我们是否应该使用异步方法来实现非常快速的IO方法,比如缓存读/写方法?
等待评估。如果等待者知道它可以在合理的时间内完成操作,则完全有权进行操作并返回完成的任务。在这种情况下,没有罚款;你只是检查一个布尔值来查看任务是否完成。
它们不会导致不必要的上下文切换。
不一定。
如果我们使用sync方法,执行将在同一个线程上完成,并且上下文切换可能不会发生。
我很困惑为什么你认为在IO操作上发生了上下文切换。 IO操作在硬件上运行,低于OS线程级别。没有任何线程可以为IO任务提供服务。
Async-await是否仅保存内存消耗(通过创建较少的线程)
等待的目的是(1)通过允许工作流变得更加异步,从而在等待高延迟结果的同时释放线程来工作,以及(2)使得更高效地使用昂贵的工作线程异步工作流的源代码类似于同步工作流的源代码。
据我所知,在同步IO的情况下,当IO发生时,线程进入睡眠模式。这意味着它不消耗CPU。这种理解是否正确?
当然可以完全倒退。 您想要消耗CPU 。你想要一直消耗尽可能多的CPU! CPU代表用户进行工作,如果它空闲,那么它无法尽快完成工作。不要雇佣一名工人然后付钱让他们入睡!雇用一名工人,一旦他们被阻止在高延迟任务上,让他们去做其他事情,这样CPU就会一直保持热度。该机器的所有者为该CPU支付了很多钱;它应该始终以100%运行才能完成工作!
让我们回到你的基本问题:
异步等待增加上下文切换
我知道一个很好的方法可以找到答案。使用await编写程序,编写另一个程序,运行它们,并测量每秒的上下文切换次数。然后你就会知道。
但我不明白为什么每秒上下文切换是一个相关指标。让我们考虑两家拥有大量客户和大量员工的银行。在银行#1,员工完成一项任务直至完成;他们从不改变背景。如果员工在等待另一个员工的结果时被阻止,他们会进入睡眠状态。在银行#2,员工在被阻止时从一个任务切换到另一个任务,并且不断地为客户请求提供服务。您认为哪家银行的客户服务更快?
答案 1 :(得分:4)
我们是否应该使用异步方法来实现非常快速的IO方法,比如缓存读/写方法?
这样的IO不会在经典意义上阻止。 "阻止"是一个松散定义的术语。通常,这意味着CPU必须等待硬件。
这种类型的IO纯粹是CPU工作,没有上下文切换。如果应用程序读取文件或套接字的速度慢于可以提供的数据,则通常会发生这种情况。在这里,异步IO根本无助于性能。我甚至不确定是否适合取消阻止UI线程,因为所有任务可能同步完成。
或者它也可以保存cpu?
它通常会增加实际负载中的CPU使用率。这是因为异步机器增加了处理,分配和同步。此外,我们需要转换到内核模式两次而不是一次(首先启动IO,然后将IO完成通知出列)。
典型工作负载使用<<< 100%CPU运行。具有> 60%CPU的生产服务器会担心我,因为没有错误余量。在这种情况下,线程池工作队列几乎总是空的。因此,在一个上下文切换上处理多个IO完成不会导致上下文切换节省。
这就是为什么CPU使用率通常会(略微)增加的原因,除非机器的CPU负载非常高并且工作队列通常能够立即提供新项目。
在服务器上,异步IO主要用于保存线程。如果您有足够的线程可用,您将实现零或负增益。特别是任何单个IO都不会快一点。
这意味着它不会消耗cpu。
在IO正在进行时让CPU不可用是一种浪费。对内核而言,IO只是一种数据结构。在它正在进行的过程中,没有CPU工作要做。
一位匿名人士说:
对于IO绑定任务,使用单独的线程来等待结果可能没有明显的性能优势。
将相同的工作推送到不同的线程肯定无助于吞吐量。这是添加工作,而不是减少工作。这是一场贝壳游戏。 (并且async IO在运行时不使用线程,因此所有这些都基于错误的假设。)
一种简单的方法来说服自己异步IO通常比同步IO花费更多的CPU是运行简单的TCP ping / pong基准同步和异步。同步更快。这是一种人为的负担,因此它只是暗示正在进行的事情,而不是一个全面的测量。