async await是否增加了上下文切换

本文关键字:上下文切换 增加 是否 await async | 更新日期: 2023-09-27 18:09:37

我知道async await是如何工作的。我知道,当执行到达等待时,它释放线程,IO完成后,它从线程池中获取线程并运行剩余的代码。这样可以有效地利用线程。但是我在一些用例中感到困惑:

    我们应该使用异步方法非常快的IO方法,如缓存读/写方法?它们不会导致不必要的上下文切换吗?如果我们使用sync方法,执行将在同一线程中完成,并且可能不会发生上下文切换。
  1. Async-await只节省内存消耗(通过创建更少的线程)。或者它也可以节省cpu ?据我所知,在同步IO的情况下,当IO发生时,线程进入睡眠模式。这意味着它不消耗cpu。这种理解正确吗?

async await是否增加了上下文切换

我知道异步等待是如何工作的。

你不是。

我知道当执行到达await时,它会释放线程

它没有。当执行到达await时,计算可等待操作数,然后检查操作是否完成。如果不是,则将方法的其余部分注册为可等待对象的延续,并将表示当前方法工作的任务返回给调用者。

这些都不是"释放线程"。相反,控制返回给调用者,调用者继续在当前线程上执行。当然,如果当前调用者是这个线程上唯一的东西,那么线程就结束了。但是没有要求异步方法是线程上的唯一调用!

IO完成后

可等待对象不一定是IO操作,但我们假设它是IO操作。

从线程池中获取线程并运行剩余的代码。

。它安排剩余的代码在正确的上下文上运行。上下文可能是一个线程池线程。它可能是UI线程。它可能是当前线程。它可以是很多东西

我们应该使用异步方法非常快的IO方法,如缓存读/写方法?

等待对象被求值。如果可等待对象知道它可以在合理的时间内完成操作,那么它完全有权利执行操作并返回已完成的任务。在这种情况下,没有惩罚;你只是在检查一个布尔值,看看任务是否完成。

它们不会导致不必要的上下文切换吗?

不一定。

如果我们使用sync方法,执行将在同一线程中完成,并且不会发生上下文切换。

我很困惑为什么你认为上下文切换发生在IO操作上。IO操作在硬件上运行,低于操作系统线程的级别。没有线程坐在那里为IO任务服务。

Async-await是否只节省内存消耗(通过创建更少的线程)

await的目的是:(1)通过允许工作流变得更加异步,从而更有效地利用昂贵的工作线程,从而释放线程在等待高延迟结果时做工作,以及(2)使异步工作流的源代码类似于同步工作流的源代码。

据我所知,在同步IO的情况下,当IO发生时,线程进入睡眠模式。这意味着它不消耗cpu。这种理解正确吗?

当然,但是你完全颠倒过来了。你想占用cpu 。您希望始终消耗尽可能多的CPU !CPU正在代表用户工作,如果它是空闲,那么它没有尽可能快地完成它的工作。不要雇佣一个工人,然后付钱让他们睡觉!雇佣一个工人,一旦他们在高延迟任务上被阻塞,就把他们安排去做其他事情,这样CPU就能一直保持热状态。那台机器的主人为那台CPU花了很多钱;它应该运行在100%的时间,有工作要做!

那么让我们回到你的基本问题:

async await是否增加上下文切换

我知道一个很好的方法来发现。使用await编写一个程序,不使用编写另一个程序,同时运行它们,并测量每秒上下文切换的次数。然后你就知道了。

但我不明白为什么每秒的上下文切换是一个相关的指标。让我们考虑两家拥有大量客户和员工的银行。在银行1,员工们在一个任务上工作,直到它完成;他们从不切换上下文。如果一名员工在等待另一名员工的结果时受阻,他们就会进入睡眠状态。在银行2号,当一个任务被阻止时,员工会从一个任务切换到另一个任务,并不断地满足客户的要求。你认为哪家银行的客户服务更快?

我们应该使用异步方法非常快的IO方法,如缓存读/写方法?

这样的IO在经典意义上不会阻塞。"阻塞"是一个定义松散的术语。通常这意味着CPU必须等待硬件。

这种类型的IO是纯粹的CPU工作,没有上下文切换。如果应用程序读取文件或套接字的速度比可以提供的数据慢,则通常会发生这种情况。在这里,异步IO对性能没有任何帮助。我甚至不确定它是否适合解锁UI线程,因为所有任务都可能同步完成。

或者它也节省cpu ?

它通常会增加实际负载中的CPU使用率。这是因为异步机制增加了处理、分配和同步。此外,我们需要转换到内核模式两次而不是一次(首先启动IO,然后解除IO完成通知队列)。

典型工作负载以<<100% CPU运行。生产服务器的CPU超过60%会让我担心,因为没有容错余地。在这种情况下,线程池工作队列几乎总是空的。因此,不会因为在一次上下文切换中处理多个IO完成而节省上下文切换时间。

这就是为什么CPU使用率通常会增加(稍微),除非机器的CPU负载非常高,并且工作队列通常能够立即交付新项目。

在服务器端,异步IO主要用于保存线程。如果您有足够的线程可用,您将实现零收益或负收益。特别是,任何单个IO都不会变得快1位。

表示不占用cpu。

当IO正在进行时,让CPU不可用是一种浪费。对于内核来说,IO只是一个数据结构。当它正在运行时,没有CPU工作要做。

一位匿名人士说:

对于io绑定的任务,使用单独的线程来等待结果可能不会有很大的性能优势。

将相同的工作推到不同的线程当然无助于提高吞吐量。这是增加的工作,而不是减少的工作。这是个骗局。(异步IO在运行时不使用线程,所以所有这些都是基于错误的假设。)

一个简单的方法来说服你自己,异步IO通常比同步IO消耗更多的CPU是运行一个简单的TCP ping/pong基准测试同步和异步。同步更快。这是一种人为的负载,所以它只是对正在发生的事情的一个提示,而不是一个全面的测量。