c# - 快速读取控制台输入

标签 c# .net input stream console

我需要从控制台的标准输入流快速读取数据。输入包含 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...

我尝试了什么:

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

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

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

  4. 在阅读开始时隐藏控制台窗口,并在阅读结束时显示它- 加速 10%

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

我注意到,在输入读取过程中 - 进程 conhost.exe 主动使用处理器。

如何加快输入的读取速度?

更新:

  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.
    

最佳答案

在您的场景中,尝试显示插入符号会浪费大量时间。您可以禁用在 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;
}

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

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);

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

进一步的优化尝试包括:

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

关于c# - 快速读取控制台输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33342340/

相关文章:

c++ - 从原始文件中取出奇偶行到新文件,然后拼接回 C++

javascript - 我无法从输入框中获取值

Android 在焦点期间劫持输入字段的 CSS?

c# - 使用 TcpClient 类连接到 smtp.live.com

c# - 如何设置radio.IsChecked = true;使用 C# 以编程方式连接到特定的单选按钮

c# - 如何让一个方法接受两种类型的数据作为参数?

.net - .NET 中的 Netbeans 平台/Eclipse RCP 替代方案

c# #region/#endregion 不匹配

c# - ISessionClient.AcceptMessageSessionAsync 中的 operationTimeout 实际上是做什么的?

c# - 是否有处理 cookie 的 C# Rest 客户端?