I need for fast reading data from standard input stream of console. Input consist of 100.000 rows with 20 chars each (2 million chars); user paste it from clipboard. My procedure works for about 3 minutes (very slowly; the target is 10 seconds). It is look like:
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...
What's I tried:
Directly: Console.Read, Console.ReadKey - the same result
Console.In: Read(), ReadLine(), ReadAsync(), ReadLineAsync(), ReadBlock(with various block size), ReadBlockAsync(), ReadToEnd(), ReadToEndAsync() - the same result
new StreamReader(Console.OpenStandardInput(buffer)) with various buffer and block size - the same result
Hide console window at start of reading, and show it when reading is finished - acceleration 10%
I tried get input data from file - it's works perfectly and fast. But I need read from __ConsoleStream.
I noticed, while input reading in progress - process conhost.exe actively uses a processor.
How can I speed up the reading of input?
upd:
Increasing/decreasing Console.BufferHeight and Console.BufferWidth has no effect
ReadFile
msdn is also slowly. But I noticed an interesting fact:
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.
Console.Read() is a method that is used to read the next character from the standard input stream. Console.readline() is a method that is used to read the next line of characters from the standard input stream. Its syntax is -: public static int Read ();
The ReadLine method reads a line from the standard input stream. (For the definition of a line, see the paragraph after the following list.) This means that: If the standard input device is the keyboard, the ReadLine method blocks until the user presses the Enter key.
In you scenario a lot of time is wasted by attempts to display inserting symbols. You can disable inserting symbols displaying in Windows (I don't know how to do that on other platforms).
Unfortunately, necessary API is not exposed by .NET (at least in 4.6.1). So you need following native methods/constants:
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;
}
and use them in following way before receiving data from clipboard:
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);
Don't forget to revert console mode flags back when you finished receiving clipboard data. I hope it will reduce your performance problem. More info about console modes can be found on GetConsoleMode
Further attempts to optimize can include:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With