std::cout 是否会降低 CPU 使用率?

4

我正在运行一个用C++编写的程序,其中CPU使用率是一个重要因素,一直在努力降低它,直到我遇到了一个意外的异常。该程序使用std::cout语句来查看性能,在删除该语句后,Windows资源监视器中程序的CPU使用情况会在4-6秒间隔的1秒内急剧上升。

如果保留std::cout语句,程序将平稳地以0-2%的CPU使用率运行,没有任何波动。而删除std::cout语句后,程序以0-2%的CPU使用率运行,但4-6秒间隔的CPU使用情况会在Windows资源监视器中高达25%。

有趣的是,增加输出字符串的大小会减少CPU峰值的高度,而减小字符串的大小则会增加CPU峰值的高度。

这是相关的代码:

float engineCompletionTime = engineTimer->getEngineCompletionTime();

/* Stops CPU from spiking */
std::cout << "Engine cycle took " << engineCompletionTime << " milliseconds." << std::endl;

if (engineCompletionTime < 14.0f) {
    std::this_thread::sleep_for(std::chrono::milliseconds((int)(14.0f - engineCompletionTime)));
}

编辑:非常感谢您的初步回应,但需要明确的是:

当std::cout代码行在程序中时,CPU不会出现峰值。

当std::cout代码行不在程序中时,CPU会出现峰值。

随着由std::cout打印的字符串大小增加,CPU峰值的大小会减少。


std::cout 是一种 I/O 操作,因此需要硬件中断以通知完成,因此相对需要更长的时间。我认为这就是你所说的峰值。实际上,它并不占用 CPU 周期,但会阻塞 CPU 并等待 I/O 操作完成。 - Ali Tavakol
尝试将std::endl更改为'\n'。使用endl会刷新缓冲区,如果在循环中频繁使用,可能会导致I/O成为瓶颈。 - Jonathon K
1
“Windows Resource Monitor”通常是一个可怕的工具,用来衡量单个小应用程序的CPU使用率(在数百个潜在的Windows服务中运行,随时可能唤醒)。通常最好使用分析器来发现代码中可以进一步优化的任何区域。 - David C. Rankin
1
通过打印引擎完成时间,您正在破坏量子叠加。虽然问题有点混乱:首先您说只有在不打印时才观察到CPU峰值,但接着您又说当打印更大的字符串时峰值会变小。 - Denis Tulskiy
考虑到在打印字符串时没有 CPU 性能峰值,那么字符串的大小如何影响这个不存在的性能峰值的大小呢? - JaMiT
不包括它会导致峰值在25%的CPU使用率处。 添加它会根据输出字符串的大小降低CPU使用率。 当输出的字符串大小与上述代码中输出的大小相同时,没有观察到明显的峰值。 - Dark Soul
2个回答

6
根据具体实现,向 std::cout 写入数据基本上涉及短暂地将控制权移交给操作系统,然后由操作系统将数据发送到终端。这在 Windows 上不是最快的过程,并且在此期间程序基本上处于空闲状态。要处理的 std::cout 数据越多,延迟时间就越长,因此程序花费的时间也越多。
如果程序花费大量时间等待输入(无论是来自另一个程序、键盘或鼠标、GUI 的“重绘屏幕”信号、操作系统还是文件系统),则其 CPU 使用率较低。基本上,CPU 使用率表示程序处于等待状态的时间所占比例。
如果程序的唯一任务是处理大量传入的数据,而没有延迟,则它根本不应该等待,如果有高 CPU 使用率也是可以接受的。另一方面,如果你有一个需要等待用户输入的程序(例如交互式应用程序),高 CPU 使用率可能会成为问题,因为这意味着即使用户没有进行任何操作,程序仍然在执行大量工作。
通常,使程序更有效率将解决这个问题。
其他导致高 CPU 使用率的原因还包括:如果您在紧密循环中检查是否发生了某些事情,而不是使用事件处理,这将导致高 CPU 使用率,因为即使程序正在等待某些事情发生,它也会主动进行检查。这就像每隔三分钟检查包裹是否到达门口,而不是等待门铃响起。如果您每隔三分钟检查一次,即使只是在等待,也会做很多工作。但是如果您只是等待门铃响起(使用事件处理),则实际上没有进行任何工作。

你所说的关于在std::cout空闲状态下具有较低的CPU使用率是有道理的,Windows资源监视工具会将其读取为不使用CPU,因为在std::cout期间程序被认为处于空闲状态。但是,如果没有std::cout,是什么导致了CPU峰值?我原本以为如果这是问题,那么在std::cout的情况下,CPU峰值会更大,因为程序会被设置为空闲状态,然后变为繁忙状态。这也没有解决std::cout输出大小如何影响CPU峰值的问题。 - Dark Soul

0

std::cout并不是特别高效(尤其在Win32上!),强制使用std::endl刷新并不能帮助解决问题 :) 通常最好自己跟踪这些日志消息,并且:完成后写入文件,每隔N次打印一次cout的平均值,或者在最后打印一个简化的摘要。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接