OutputBase.Write 会为每个清洁单元发出一个 Cursor 定位调用,使每次重绘都需要执行 rows × cols 次系统调用。
作者: Scripturd创建于 2026年9月7日更新于 2026年9月7日
标签bug
Terminal.Gui/Drivers/Output/OutputBase.cs 中的 Write(IOutputBuffer) (从 2.4.17 反编译而来):
for (int j = num; j < cols; j++)
{
lastCol = -1;
int outputWidth = 0;
for (; j < cols; j++)
{
bool flag3 = IsRasterCoveredBlankCell(buffer, i, j, rasterCellRectangles);
if (!buffer.Contents[i, j].IsDirty | flag3) // cell is CLEAN
{
if (flag3) { buffer.Contents[i, j].IsDirty = false; }
if (stringBuilder.Length > 0)
WriteToConsole(stringBuilder, ref lastCol, ref outputWidth);
else if (lastCol == -1)
lastCol = j;
if (lastCol + 1 < cols) { lastCol++; }
SetCursorPositionImpl(lastCol, i); // ← one I/O op per skipped cell
continue;
}
// ...
}
}lastCol 每次迭代增加 1,因此位置总是不同,调用总是执行 I/O:
ansi—AnsiOutput.SetCursorPositionImpl→Write(ReadOnlySpan<char>),它分配一个新的StringBuilder,执行Encoding.UTF8.GetBytes,并为 ~7 字节的CSI r;cH发出自己的WriteFile。dotnet—NetOutput.SetCursorPositionImpl→Console.SetCursorPosition,位于一个简单的try {} catch {}中。它调用ConsolePal.GetBufferInfo,如果缓冲区无法查询,则 每个单元格都会抛出和吞噬一个 Win32 异常。
测量结果
内容来源: tui-cs/Terminal.Gui