快速读取控制台输入

Mar*_*dik 13 .net c# console input stream

我需要从控制台的标准输入流快速读取数据.输入包含100.000行,每行20个字符(200万个字符); 用户从剪贴板粘贴它.我的程序工作约3分钟(非常慢;目标是10秒).它看起来像:

var inputData = new string[100000]; // 100.000 rows with 20 chars
for (int i = 0; i < 100000; i++) // Cycle duration is about 3 minutes...
{
    inputData[i] = Console.ReadLine();
}
// some processing...
Run Code Online (Sandbox Code Playgroud)

我尝试了什么:

  1. 直接:Console.Read,Console.ReadKey - 相同的结果

  2. Console.In:Read(),ReadLine(),ReadAsync(),ReadLineAsync(),ReadBlock(具有各种块大小),ReadBlockAsync(),ReadToEnd(),ReadToEndAsync()- 相同的结果

  3. 新的StreamReader(Console.OpenStandardInput(缓冲区))具有各种缓冲区和块大小- 相同的结果

  4. 在读取开始时隐藏控制台窗口,并在读取完成时显示- 加速10%

  5. 我尝试从文件中获取输入数据 - 它的工作完美而快速.但我需要从__ConsoleStream中读取.

我注意到,当输入读取正在进行时 - 进程conhost.exe主动使用处理器.

如何加快输入读数?

UPD:

  1. 增加/减少Console.BufferHeight和Console.BufferWidth无效

  2. ReadFile msdn也慢慢来.但我注意到一个有趣的事实:

    ReadFile(handle, buffer, bufferSize, out bytesCount, null);
    // bufferSize may be very big, but buffer obtains no more than one row (with \r\n).
    // So, it seems that data passed into InputStream row-by-row syncroniously.
    
    Run Code Online (Sandbox Code Playgroud)

Dli*_*Lag 2

在您的场景中,尝试显示插入符号会浪费大量时间。您可以禁用在 Windows 中显示的插入符号(我不知道如何在其他平台上执行此操作)。

不幸的是,.NET 没有公开必要的 API(至少在 4.6.1 中)。所以你需要以下本机方法/常量:

internal class NativeMethods
{
    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern bool SetConsoleMode(IntPtr hConsoleHandle, int mode);

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern bool GetConsoleMode(IntPtr hConsoleHandle, out int mode);

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr GetStdHandle(int nStdHandle);

    internal const int STD_INPUT_HANDLE = -10;
    internal const int ENABLE_ECHO_INPUT = 0x0004;
}
Run Code Online (Sandbox Code Playgroud)

并在从剪贴板接收数据之前按以下方式使用它们:

var handle = NativeMethods.GetStdHandle(NativeMethods.STD_INPUT_HANDLE);
int mode; 
NativeMethods.GetConsoleMode(handle, out mode);
mode &= ~NativeMethods.ENABLE_ECHO_INPUT; // disable flag
NativeMethods.SetConsoleMode(handle, mode);
Run Code Online (Sandbox Code Playgroud)

当您完成接收剪贴板数据后,不要忘记恢复控制台模式标志。我希望它能减少您的性能问题。有关控制台模式的更多信息可以在GetConsoleMode上找到

进一步的优化尝试可以包括:

  • 重写没有锁的控制台读取代码(因为它是在 .NET 中实现的),并确保此时没有任何线程与控制台一起工作。相当昂贵的任务。
  • 尝试找到增加标准输入缓冲区大小的方法。但我不确定这是否可能。
  • 不要忘记在发布版本中进行测试而不进行调试%)