术语“CPU绑定”和“I / O绑定”是什么意思?
答案 0 :(得分:362)
非常直观:
如果CPU速度更快,程序就会受CPU限制,即它大部分时间都花在CPU上(进行计算)。计算π新数字的程序通常会受CPU限制,它只是处理数字。
如果I / O子系统更快,程序将受到I / O限制。哪个确切的I / O系统可能会有所不同;我通常将它与磁盘相关联,但当然网络或通信也很常见。一个程序通过一个巨大的文件查找某些数据可能会成为I / O绑定,因为瓶颈就是从磁盘读取数据(实际上,这个例子可能有点老式,现在数百MB / s从SSD进来。)
答案 1 :(得分:200)
CPU绑定表示进程进度的速率受CPU速度的限制。对一小组数字执行计算的任务(例如乘以小矩阵)很可能受CPU限制。
I / O界限表示进程进度的速率受I / O子系统速度的限制。处理来自磁盘的数据的任务(例如,计算文件中的行数)可能受I / O限制。
内存绑定表示进程进度的速率受可用内存量和内存访问速度的限制。处理大量内存数据的任务(例如乘以大矩阵)很可能是Memory Bound。
缓存绑定表示进程进度受可用缓存的数量和速度限制的速率。一个简单处理更多数据而不是缓存中的任务的任务将被缓存限制。
I / O Bound会慢于Memory Bound会慢于Cache Bound会比CPU Bound慢。
受I / O限制的解决方案不一定要获得更多内存。在某些情况下,可以围绕I / O,内存或缓存限制设计访问算法。请参阅 Cache Oblivious Algorithms。
答案 2 :(得分:33)
<强>多线程强>
在这个答案中,我将研究一个区分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的联想ThinkPad P51笔记本电脑:Intel Core i7-7820HQ CPU(4核/ 8线程),RAM:2x Samsung M471A2K43BB1-CRC(2x 16GiB)我得到的结果如下: / p>
请注意,运行之间存在很多差异。但是我不能进一步增加阵列大小,因为我已经在8GiB了,而且我今天不能在多次运行中统计数据。然而,这似乎是在进行许多手动运行后的典型运行。
基准代码:
POSIX C pthread
source code在图表中使用。
这是一个产生类似结果的C++ version。
我不知道足够的计算机体系结构来完全解释曲线的形状,但有一件事是清楚的:由于我使用了所有8个线程,计算速度不会像天真预期的那样快8倍!出于某种原因,2/3线程是最佳的,增加更多只会使事情变得更慢。
将此与CPU绑定工作进行比较,实际上速度提高了8倍:What do 'real', 'user' and 'sys' mean in the output of time(1)?
所有处理器共享一条链接到RAM的内存总线的原因是:
CPU 1 --\ Bus +-----+
CPU 2 ---\__________| RAM |
... ---/ +-----+
CPU N --/
所以内存总线很快成为瓶颈,而不是CPU。
这是因为添加两个数字需要一个CPU周期,2016年硬件中的内存读取大约需要100 CPU cycles。
因此,每个输入数据字节完成的CPU工作量太小,我们称之为IO绑定过程。
进一步加速计算的唯一方法是使用新的存储器硬件加速单个存储器访问,例如: Multi-channel memory
例如,升级到更快的CPU时钟不会非常有用。
其他示例
矩阵乘法在RAM和GPU上受CPU限制。输入包含:
2 * N**2
数字,但是:
N ** 3
乘法完成,这足以使并行化对于实际的大N来说是值得的。
这就是存在以下并行CPU矩阵乘法库的原因:
缓存使用对实现速度有很大影响。例如,请参阅此didactic GPU comparison example。
GPU在将数据传输到CPU时存在IO瓶颈。
它们的设计使得渲染输出(像素矩形)可以直接输出到视频内存,以避免CPU往返。
网络是典型的IO绑定示例。
即使我们发送一个字节的数据,仍然需要很长时间才能到达目的地。
并行化HTTP请求等小型网络请求可以带来巨大的性能提升。
如果网络已经满负荷运行(例如下载torrent),并行化仍然可以增加延迟(例如,您可以同时加载网页&#34;&#34;)。
虚拟C ++ CPU绑定操作,它接受一个数字并对其进行大量处理:
如何确定您是CPU还是IO绑定
非RAM IO绑定到磁盘,网络:ps aux
,然后是CPU% / 100 < n threads
。如果是,那么你是IO界限,例如阻塞read
只是在等待数据,调度程序正在跳过该进程。然后使用其他工具(如sudo iotop
)来确定哪个IO是完全正确的问题。
或者,如果执行速度很快,并且您参数化线程数,则可以从time
轻松地看到,随着CPU绑定工作的线程数增加,性能会提高:What do 'real', 'user' and 'sys' mean in the output of time(1)?
RAM-IO绑定:很难说,因为RAM等待时间它包含在CPU%
测量中。也许你能做的最好的事情就是估计缓存未命中。
另见:
CPython Global Intepreter Lock(GIL)
作为一个简单的案例研究,我想指出Python全局解释器锁(GIL):What is the global interpreter lock (GIL) in CPython?
此CPython实现细节可防止多个Python线程有效地使用受CPU限制的工作。 CPython docs说:
CPython实现细节:在CPython中,由于Global Interpreter Lock,只有一个线程可以同时执行Python代码(即使某些面向性能的库可能会克服此限制)。如果您希望应用程序更好地利用多核计算机的计算资源,建议您使用
multiprocessing
或concurrent.futures.ProcessPoolExecutor
。但是,如果要同时运行多个I / O绑定任务,则线程仍然是一个合适的模型。
因此,这里我们有一个例子,其中CPU绑定内容不合适,I / O绑定是。
答案 3 :(得分:28)
CPU绑定意味着程序受到CPU或中央处理单元的瓶颈,而I/O绑定意味着程序受到I / O或输入/输出的瓶颈,例如读取或写入磁盘,网络等等。
通常,在优化计算机程序时,人们会试图找出瓶颈并消除它。知道你的程序是CPU绑定有帮助的,所以不会不必要地优化其他东西。
[并且通过“瓶颈”,我的意思是让你的程序变得比它原本要慢的东西。]
答案 4 :(得分:16)
另一种表达同一想法的方法:
如果加速CPU没有加快程序的速度,可能会I/O绑定。
如果加速I / O(例如使用更快的磁盘)没有帮助,那么您的程序可能受CPU限制。
(我使用“可能是”因为你需要考虑其他资源。记忆就是一个例子。)
答案 5 :(得分:9)
当您的程序等待I/O(即磁盘读/写或网络读/写等)时,即使程序停止,CPU也可以自由执行其他任务。程序的速度主要取决于IO的发生速度,如果你想加快速度,你需要加快I / O.
如果你的程序运行了很多程序指令而不是等待I / O,那么它就被认为是CPU绑定的。加速CPU将使程序运行得更快。
在任何一种情况下,加速程序的关键可能不是加速硬件,而是优化程序以减少所需的IO或CPU数量,或让它同时进行I / O操作。是CPU密集型的东西。
答案 6 :(得分:5)
I / O bound是指完成计算所花费的时间主要取决于等待输入/输出操作完成所花费的时间的条件。
这与CPU绑定的任务相反。当请求数据的速率低于其消耗速率时,或者换句话说,请求数据所花费的时间多于处理数据的时间,就会出现这种情况。
答案 7 :(得分:4)
IO绑定进程:花费更多时间做IO而不是计算,有很多 短CPU爆发。 CPU绑定进程:花费更多时间进行计算,很少有很长的CPU突发
答案 8 :(得分:4)
当执行期间的算术/逻辑/浮点(A / L / FP)性能大部分接近处理器的理论峰值性能时,应用程序受CPU限制(制造商提供的数据由处理器确定)。处理器的特征:内核数,频率,寄存器,ALU,FPU等)。
在实时应用程序中很难达到窥视性能,这并不是说不可能。大多数应用程序在执行的不同部分访问内存,并且处理器在几个周期内未执行A / L / FP操作。由于内存和处理器之间存在距离,因此称为
如果要接近CPU峰值性能,则可以尝试重用高速缓存中的大多数数据,以避免需要来自主内存的数据。利用此功能的一种算法是矩阵矩阵乘法(如果两个矩阵都可以存储在高速缓存中)。发生这种情况的原因是,如果矩阵的大小为n x n
,那么您只需要使用2 n^3
个FP数量的数据来执行2 n^2
个操作。另一方面,例如,矩阵加法比矩阵乘法是CPU较少的应用程序或内存较多的应用程序,因为它仅需要具有相同数据的n^2
FLOP。
下图显示了使用天真算法在英特尔i5-9300H中用于矩阵加法和矩阵乘法的FLOP:
请注意,正如预期的那样,矩阵乘法的性能大于矩阵加法的性能。通过运行此repository中可用的test/gemm
和test/matadd
,可以复制这些结果。
我还建议看到J. Dongarra给出的video。
答案 9 :(得分:3)
异步编程的核心是Task和Task对象,它们 对异步操作进行建模。它们受异步和 等待关键字。在大多数情况下,该模型非常简单:
对于受I / O约束的代码,您等待操作返回Task或 异步方法中的任务。
对于受CPU约束的代码,您需要等待在CPU上启动的操作 具有Task.Run方法的后台线程。
神奇的关键字是await关键字。它可以控制 执行的方法的调用者,它最终允许 UI响应或服务具有弹性。
I/O-Bound Example: Downloading data from a web service
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-bound Example: Performing a Calculation for a Game
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 。您不应该使用任务并行库。的原因 Async in Depth文章对此进行了概述。
如果您的工作受CPU限制,并且您关心响应速度, 使用异步并等待,但使用以下命令在另一个线程上产生工作 Task.Run。如果这项工作适合于并发和并行处理, 您还应该考虑使用Task Parallel Library。
答案 10 :(得分:0)
I / O绑定过程: - 如果进程的大部分生命周期都花费在i / o状态,那么该进程是一个i / o绑定进程。示例:-calculator,internet explorer
CPU绑定过程: - 如果过程生命的大部分时间都花在cpu上,那么它就是cpu绑定过程。