C++中最快的终端文本打印函数是什么?还有更快方法吗?
控制台3D应用的高效文本打印优化方案
我正在开发一款控制台3D旋转立方体应用,需要实现最快的控制台文本打印。我用Very Sleepy性能分析器测试了几种方法的耗时(循环5000次打印全屏字符):
- printf:192.2s
- std::print:0.2s
- std::cout:0.2s
- WriteConsoleOutputA:1.1s
目前std::cout和std::print表现最优,但想知道有没有其他能接收控制台尺寸字符数组的更快打印方法。
优化现有方法的空间
首先可以对当前的std::cout和std::print代码做针对性优化,进一步压缩耗时:
- 关闭std::cout与C标准库的同步
默认情况下std::cout会和stdio保持同步,关闭该特性可大幅减少底层开销:
#include <windows.h> #include <iostream> int main() { // 核心优化:关闭同步并解除cin与cout的绑定 std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr); int i; HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO screen; GetConsoleScreenBufferInfo(console, &screen); short columns = screen.srWindow.Right - screen.srWindow.Left + 1; short rows = screen.srWindow.Bottom - screen.srWindow.Top + 1; char characters[columns * rows + 1]; for (i = 0; i < columns * rows; i++) { characters[i] = '.'; } characters[columns * rows] = '\0'; for (i = 0; i < 5000; i++) { std::cout << characters; SetConsoleCursorPosition(console, (COORD){0, 0}); } return 0; }
- 避免std::print的重复字符串构造
原代码中每次循环都构造std::string(characters),将字符串预构造在循环外,可消除重复的内存分配与拷贝开销:
#include <windows.h> #include <print> #include <string> int main() { int i; HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO screen; GetConsoleScreenBufferInfo(console, &screen); short columns = screen.srWindow.Right - screen.srWindow.Left + 1; short rows = screen.srWindow.Bottom - screen.srWindow.Top + 1; char characters[columns * rows + 1]; for (i = 0; i < columns * rows; i++) { characters[i] = '.'; } characters[columns * rows] = '\0'; // 预构造输出字符串,循环内复用 std::string output_str(characters); for (i = 0; i < 5000; i++) { std::print("{}", output_str); SetConsoleCursorPosition(console, (COORD){0, 0}); } return 0; }
未提及的高效方法:直接调用WriteConsoleA
WriteConsoleA是Windows原生API,直接向控制台输出缓冲区写入字符,跳过C++标准库的中间封装,处理大字符数组时效率更优,且可直接接收char数组:
#include <windows.h> int main() { int i; HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO screen; GetConsoleScreenBufferInfo(console, &screen); short columns = screen.srWindow.Right - screen.srWindow.Left + 1; short rows = screen.srWindow.Bottom - screen.srWindow.Top + 1; char characters[columns * rows + 1]; for (i = 0; i < columns * rows; i++) { characters[i] = '.'; } characters[columns * rows] = '\0'; DWORD bytes_written; for (i = 0; i < 5000; i++) { WriteConsoleA(console, characters, columns * rows, &bytes_written, nullptr); SetConsoleCursorPosition(console, (COORD){0, 0}); } return 0; }
该方法直接与控制台内核交互,无标准库的额外开销,对于固定尺寸的全屏输出,速度会优于优化后的std::cout/std::print。
极限优化:锁定控制台缓冲区
若追求极致性能,可锁定控制台屏幕缓冲区内存,直接修改缓冲区内容后一次性写入,减少API调用的重复开销:
#include <windows.h> #include <cstdlib> int main() { int i; HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO screen; GetConsoleScreenBufferInfo(console, &screen); short columns = screen.srWindow.Right - screen.srWindow.Left + 1; short rows = screen.srWindow.Bottom - screen.srWindow.Top + 1; // 分配缓冲区内存 COORD buffer_size = {columns, rows}; CHAR_INFO* buffer = static_cast<CHAR_INFO*>(malloc(sizeof(CHAR_INFO) * columns * rows)); if (!buffer) return 1; // 初始化缓冲区内容 for (i = 0; i < columns * rows; i++) { buffer[i].Char.AsciiChar = '.'; buffer[i].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; } // 修正写入区域:SMALL_RECT右边界为columns-1,避免越界 SMALL_RECT write_area = {0, 0, static_cast<short>(columns - 1), static_cast<short>(rows - 1)}; for (i = 0; i < 5000; i++) { // 若需实时更新画面,在此修改buffer内容即可 WriteConsoleOutputA(console, buffer, buffer_size, {0, 0}, &write_area); } free(buffer); return 0; }
此方法在频繁更新全屏内容时,仅需修改内存中的缓冲区,再一次性写入控制台,大幅降低了API调用的额外消耗,性能优于普通WriteConsoleOutputA调用。
内容的提问来源于stack exchange,提问作者Big
相关产品推荐
相关产品推荐

