'Any faster way to set console colors?

Was profiling my code and found that the way we are doing colored console text is very expensive (majority of the runtime).

    DateTime dt = DateTime.Now;

    for (int i = 0; i <= 20000; i++)
    {
        ConsoleColor cf = Console.ForegroundColor;
        ConsoleColor cb = Console.BackgroundColor;
        Console.ForegroundColor = ConsoleColor.Red;
        Console.BackgroundColor = ConsoleColor.Blue;
        Console.WriteLine("Hello World");
        Console.ForegroundColor = cf;
        Console.BackgroundColor = cb;
    }

    System.Diagnostics.Debug.WriteLine((DateTime.Now - dt).TotalMilliseconds);

This simple loop takes 2.8 seconds to run on my machine. If I just do the WriteLine, its only 600ms.

Now, before I get troll answers :) asking why I keep setting the color when its hardcoded, THIS IS TEST CODE, in the real code, the foreground and background colors are calculated on a few different factors. That part is irrelevant. This code is just assuming that the color will change and thus saves the originals, changes the colors, then changes it back to the original.

I've also tried using the native SetConsoleTextAttribute method through pinvoke since using ILSpy, it seemed like the Console.xxx methods were doing a lot of extra crap, but I got about the same timings.



Solution 1:[1]

Not really. As you've already noted, the properties built in to Console interact with SetConsoleTextAttribute directly, which is the way to set console output properties in Windows.


If ANSI colors are an option, which would be substantial changes to logic you have working with console colors, it is faster. A minimal case

for (int i = 0; i <= 20000; i++)
{
    Console.WriteLine("\x1b[31m\x1b[44mHello World\x1b[39m\x1b[49m");
}

runs in about 1200 ms on my machine, compared to about 7000 ms with the Console.xxxColor properties.

You'll need a compatible shell. Ansicon works.


With ANSI colors, you can additionally batch your output for even more times savings. Even batches of lines of 20 chop the run time above in half.* If you're spamming to the console for whatever reason, that could help significantly.

*On my machine.

Solution 2:[2]

See this answer to "How can I write fast colored output to Console?" and note this solution requires p-invoking of WriteConsoleOutput.

The color information is in the CharInfo struct, using Console.ForegroundColor in the lower 4 bits and BackgroundColor in the upper 4 bits of the short Attributes field.

Here is the constructor I use for the struct:

public CharInfo(char character, ConsoleColor? foreground = null, ConsoleColor? background = null) {
    this.Char = new CharUnion() { UnicodeChar = character };
    this.Attributes = (ushort)((int)(foreground ?? 0) | (((int)(background ?? 0)) << 4));
}

(you will also need to have CharSet=CharSet.Unicode in a couple places in the [StructLayout...] attributes to get Unicode to work)

Do some buffering by constructing an array CharInfo[] sized for the console window, then flush it to screen all at once for immensely-fast* updates!

*Fast relative Console.Write... methods at least. 160x80 can still take over 100ms.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jdphenix
Solution 2