术语“ CPU绑定”和“ I / O绑定”是什么意思?


Answers:


452

这很直观:

如果程序在CPU更快的情况下运行得更快,则该程序受CPU限制,即,程序大部分时间仅使用CPU(进行计算)。计算π的新数字的程序通常受CPU限制,只是计算数字。

如果I / O子系统更快,则程序运行得更快,则该程序受I / O约束。确切的I / O系统意味着什么,可能会有所不同。我通常将其与磁盘关联,但是当然,一般而言,联网或通信也很常见。通过大文件查找某些数据的程序可能会成为I / O绑定,因为瓶颈是然后从磁盘读取数据(实际上,此示例如今可能已经过时,具有数百MB / s的速度)。来自SSD)。


这如何与理解移动设备上的HTTP通信联系在一起?我已经看到使用java.nio操作会导致 CPU使用率激增。
IgorGanapolsky

I / O是“输入/输出”。
车同志

246

CPU绑定是指进程进行的速度受CPU速度的限制。在少量数字上执行计算(例如,将较小的矩阵相乘)的任务很可能受CPU限制。

I / O绑定是指进程进行的速率受I / O子系统的速度限制。处理磁盘数据的任务(例如,计算文件中的行数)很可能受I / O约束。

内存限制是指进程进行的速度受可用内存量和该内存访问速度的限制。处理大量内存数据(例如,乘以大型矩阵)的任务很可能是“内存绑定”。

高速缓存绑定是指进程进度受可用高速缓存的数量和速度限制的速率。仅处理超出缓存容量的更多数据的任务将受到缓存限制。

I / O界限将比内存界限慢,而缓存界限将比CPU界限慢。

受I / O约束的解决方案不一定获得更多的内存。在某些情况下,可以围绕I / O,内存或缓存限制来设计访问算法。请参阅缓存遗忘算法


72

多线程

在这个答案中,我将研究一种区分CPU与IO受限工作的重要用例:编写多线程代码时。

RAM I / O绑定示例:矢量和

考虑一个对单个向量的所有值求和的程序:

#define SIZE 1000000000
unsigned int is[SIZE];
unsigned int sum = 0;
size_t i = 0;
for (i = 0; i < SIZE; i++)
    /* Each one of those requires a RAM access! */
    sum += is[i]

通过在每个现代内核上平均分配阵列来并行化这一点,在通用的现代台式机上用途有限。

例如,在我的Ubuntu 19.04上,带有CPU的Lenovo ThinkPad P51笔记本电脑:Intel Core i7-7820HQ CPU(4核/ 8线程),RAM:2x Samsung M471A2K43BB1-CRC(2x 16GiB)我得到如下结果:

在此处输入图片说明

绘制数据

请注意,运行之间有很多差异。但是,由于我已经在8GiB上工作,因此无法进一步增加阵列大小,并且今天我不打算进行多次运行的统计。但是,在进行许多手动运行之后,这似乎是一种典型的运行。

基准代码:

我不了解足够的计算机体系结构来完全解释曲线的形状,但是有一点很清楚:由于我使用了所有8个线程,因此计算速度并没有像天真预期的那样快8倍!由于某些原因,2和3个线程是最佳的,添加更多线程只会使事情变慢。

将此与CPU限制的工作进行比较,它实际上的确快了8倍:time(1)输出中的“ real”,“ user”和“ sys”是什么意思?

这是所有处理器共享链接到RAM的单个内存总线的原因:

CPU 1   --\    Bus    +-----+
CPU 2   ---\__________| RAM |
...     ---/          +-----+
CPU N   --/

因此内存总线很快成为瓶颈,而不是CPU。

发生这种情况是因为在2016年硬件中,将两个数字相加会占用一个CPU周期,而内存读取则需要约100个CPU周期

因此,每字节输入数据完成的CPU工作量太小,我们将其称为IO绑定过程。

进一步加快计算速度的唯一方法是使用新的内存硬件(例如多通道内存)加快单个内存的访问。

例如,升级到更快的CPU时钟将不是很有用。

其他例子

如何找出您是否受CPU或IO约束

将非RAM IO绑定为磁盘,网络:ps aux,则为CPU% / 100 < n threads。如果是,则您受IO限制,例如,阻塞reads在等待数据,而调度程序正在跳过该过程。然后使用其他工具sudo iotop来确定确切的问题是哪个IO。

或者,如果执行速度很快,并且您对线程数进行了参数化,则可以很容易地看到,time随着CPU绑定工作的线程数增加,性能会提高:“ real”,“ user”和“ sys”分别是什么意思time(1)的输出?

RAM-IO限制:很难说,因为RAM等待时间包含在CPU%测量中,另请参见:

一些选项:

  • 英特尔顾问Roofline(非免费):https : //software.intel.com/zh-cn/articles/intel-advisor-roofline (存档)“ Roofline图表是与硬件限制有关的应用程序性能的直观表示,包括内存带宽和计算峰值。”

GPU

首次将输入数据从常规CPU可读RAM传输到GPU时,GPU会有IO瓶颈。

因此,对于受CPU约束的应用程序,GPU只能比CPU更好。

但是,一旦将数据传输到GPU,由于GPU:

  • 比大多数CPU系统具有更多的数据本地化,因此某些内核可以比其他内核更快地访问数据

  • 通过跳过所有尚未准备立即操作的数据来利用数据并行性并牺牲延迟。

    由于GPU必须对大型并行输入数据进行操作,因此最好跳过可能可用的下一个数据,而不是等待当前数据可用并阻塞所有其他操作,例如CPU

因此,如果您的应用程序使用以下处理器,则GPU可以比CPU更快。

  • 可以高度并行化:不同数据块可以同时彼此分开处理
  • 每个输入字节需要足够多的操作(与例如矢量加法不同,矢量加法仅对每个字节进行一次加法)
  • 有大量的输入字节

这些设计选择最初是针对3D渲染的应用程序,其主要步骤如OpenGL中的着色器所示,我们需要它们做什么?

  • 顶点着色器:将一堆1x4向量乘以4x4矩阵
  • 片段着色器:根据三角形的每个相对位置计算三角形的每个像素的颜色

因此我们得出结论,这些应用程序受CPU限制。

随着可编程GPGPU的问世,我们可以观察到几种GPGPU应用程序,它们是CPU绑定操作的示例:

也可以看看:

CPython全局解释器锁(GIL)

作为快速案例研究,我想指出一下Python全局解释器锁(GIL):CPython中的全局解释器锁(GIL)是什么?

这个CPython实现细节阻止了多个Python线程有效地使用CPU绑定的工作。在CPython的文档说:

CPython实现细节:在CPython中,由于使用了全局解释器锁,因此只有一个线程可以一次执行Python代码(即使某些面向性能的库可能克服了此限制)。如果您希望应用程序更好地利用多核计算机的计算资源,建议使用multiprocessingconcurrent.futures.ProcessPoolExecutor。但是,如果您要同时运行多个I / O绑定任务,则线程化仍然是合适的模型。

因此,这里有一个示例,其中CPU绑定的内容不适合,而I / O绑定的则不适合。


1
伙计,你如何设法胜任如此这样的写作?
Mikayil Abdullayev

1
@MikayilAbdullayev谢谢!我倾向于只回答“重要问题”,在学习新的相关知识时,我会一遍又一遍地回到他们身上。
Ciro Santilli郝海东冠状病六四事件法轮功

31

CPU绑定意味着程序受到CPU或中央处理器的瓶颈,而I / O绑定意味着程序受到I / O或输入/输出(例如对磁盘,网络的读写)的瓶颈。

通常,在优化计算机程序时,人们会尝试找出瓶颈并消除瓶颈。知道您的程序受CPU限制是有帮助的,这样您就不必不必要地优化其他内容。

[“瓶颈”是指使您的程序运行缓慢的原因。]


21

表达相同想法的另一种方法:

  • 如果加速CPU不能加快程序速度,则可能是I / O限制。

  • 如果加速I / O(例如使用更快的磁盘)无济于事,则您的程序可能受CPU限制。

(我用“可能是”是因为您需要考虑其他资源。内存就是一个例子。)


11

当程序正在等待I / O(即磁盘读/写或网络读/写等)时,即使程序已停止,CPU也可以自由执行其他任务。程序的速度主要取决于IO发生的速度,如果要加快速度,则需要加快I / O的速度。

如果您的程序正在运行大量程序指令,而不是在等待I / O,则认为它与CPU绑定。加速CPU将使程序运行更快。

无论哪种情况,加快程序速度的关键可能不是加快硬件速度,而是优化程序以减少所需的IO或CPU数量,或者在占用大量CPU资源的同时进行I / O操作。东西。


6

I / O界限是指一种条件,其中完成计算所需的时间主要由等待输入/输出操作完成所花费的时间来确定。

这与受CPU约束的任务相反。当请求数据的速率比消耗数据的速率慢,或者换句话说,请求数据花费的时间多于处理数据的时间时,就会出现这种情况。


6

IO绑定进程:花在执行IO上的时间多于计算时间,CPU突发短。受CPU限制的进程:花更多时间进行计算,很少有很长的CPU突发


2

看看微软怎么说。

异步编程的核心是Task和Task对象,它们对异步操作进行建模。它们由async和await关键字支持。在大多数情况下,该模型非常简单:

  • 对于绑定到I / O的代码,您需要等待一个操作,该操作将在异步方法内部返回Task或Task。

  • 对于受CPU约束的代码,您需要等待通过Task.Run方法在后台线程上启动的操作。

关键字await是魔术发生的地方。它将控制权交给执行等待的方法的调用者,最终允许UI响应或服务具有弹性。

I / O绑定示例:从Web服务下载数据

private readonly HttpClient _httpClient = new HttpClient();

downloadButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI as the request
    // from the web service is happening.
    //
    // The UI thread is now free to perform other work.
    var stringData = await _httpClient.GetStringAsync(URL);
    DoSomethingWithData(stringData);
};

受CPU限制的示例:为游戏执行计算

private DamageResult CalculateDamageDone()
{
    // Code omitted:
    //
    // Does an expensive calculation and returns
    // the result of that calculation.
}

calculateButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI while CalculateDamageDone()
    // performs its work.  The UI thread is free to perform other work.
    var damageResult = await Task.Run(() => CalculateDamageDone());
    DisplayDamage(damageResult);
};

上面的示例显示了如何使用异步和等待来进行I / O绑定和CPU绑定的工作。您可以确定何时需要做的工作是受I / O约束或受CPU约束的关键,因为它会极大地影响代码的性能,并可能导致滥用某些构造。

在编写任何代码之前,您应该问两个问题:

您的代码会“等待”某事,例如数据库中的数据吗?

  • 如果您的回答是“是”,则您的工作受I / O约束。

您的代码会执行非常昂贵的计算吗?

  • 如果回答“是”,则说明您的工作受CPU限制。

如果您的工作受I / O限制,请使用async并等待而无需 Task.Run。您不应该使用任务并行库。深度异步中概述了这样做的原因文章中。

如果您的工作受CPU限制并且您关心响应性,请使用async和await,但使用Task.Run在另一个线程上启动工作。如果该工作适合于并发性和并行性,则还应该考虑使用Task Parallel Library


2

当执行期间的算术/逻辑/浮点(A / L / FP)性能大部分接近处理器的理论峰值性能时(该数据由制造商提供,并由处理器的特性确定),该应用程序受CPU限制。处理器:内核数,频率,寄存器,ALU,FPU等)。

要说真实的性能很难在现实世界中的应用程序中实现,这并不是说不可能。大多数应用程序在执行的不同部分访问内存,并且处理器在几个周期内未执行A / L / FP操作。由于内存和处理器之间存在距离,因此这称为冯·诺依曼限制

如果要接近CPU峰值性能,则可以尝试重用高速缓存中的大多数数据,以避免需要来自主内存的数据。利用此功能的算法是矩阵矩阵乘法(如果两个矩阵都可以存储在高速缓存中)。发生这种情况的原因是,如果矩阵是大小,n x n那么您只需要2 n^3使用2 n^2FP数量的数据就可以进行操作。另一方面,例如,与矩阵乘法相比,矩阵加法是CPU限制较少的应用程序,或者是存储器限制较大的应用程序,因为它仅需要矩阵乘法n^2具有相同数据的FLOP。

下图显示了使用天真算法在英特尔i5-9300H中用于矩阵加法和矩阵乘法的FLO​​P:

矩阵加法和矩阵乘法之间的FLOP比较

注意,正如预期的那样,矩阵乘法的性能大于矩阵加法的性能。这些结果可以通过运行来复制test/gemmtest/matadd在此存储库中可用

我还建议您观看J. Dongarra提供的有关此效果的视频


1

I / O绑定进程:-如果进程生命周期的大部分时间都处于I / O状态,则该进程就是AI / O绑定进程。例如:-calculator,internet Explorer

CPU绑定进程:-如果进程寿命的大部分时间都花在cpu上,那么它就是cpu绑定进程。


8
计算器将如何成为IO绑定过程?肯定是受CPU限制的。如果您的计算器大部分时间都因为访问网络或磁盘而受阻,那么我建议这是有问题的。
rickerbh 2012年

6
我认为计算器示例很清楚:大多数情况下,它等待用户按下按钮,因此等待I / O。
psp 2015年

1
@psp是正确的,但是由于它的名称“ calculator”,因此从表面上看,计算器示例仍然难以理解。这意味着该程序的主要目的是执行长时间的cpu计算,但是如果您在台式机上看一下计算器,这是一个非常简单的计算器,仅需完成纳秒级的计算即可。因此,大多数情况下,它在等待用户输入,即IO。
Calicoder '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.