Home All Groups Group Topic Archive Search About

Why is system.console so slow?

Author
3 Feb 2007 8:35 AM
Nik Coughlin
System.Console is really slow.  I wanted to make a retro text-only console
application game (a roguelike), but I can't get decent performance out of
it.  Does anyone know how to get decent performance out of it?  Is there
some way of buffering the text before outputting it?  Here's my test code
(slow!):

Random r = new Random();

Console.Clear( );

while ( true ) {
  for ( int y = 0; y < 20; y++ ) {
    for ( int x = 0; x < 70; x++ ) {
      Console.SetCursorPosition( x, y );
      Console.ForegroundColor = (ConsoleColor) r.Next( 16 );
      Console.Write( 'x' );
    }
  }
}

The only way I could get it to run at a decent speed was by using
Console.WriteLine on each row, but that means I can't set the color for
individual characters.

As an aside note, I fired up the oldest programming IDE I could find
(QuickBasic 4.5, ah the nostalgia) and tried this:

CLS

DO
  FOR y% = 1 TO 20
    FOR x% = 1 TO 70
      LOCATE y%, x%
      COLOR INT(RND * 16)
      PRINT "x"
    NEXT x%
  NEXT y%
LOOP

It was blazingly fast.  Surely a modern framework like .Net can do fast
console drawing, I must be missing something.

Please tell me I don't have to use the Win32 API :)  I'm aiming to have it
work in Mono too, so I want to stay in managed code.

Author
3 Feb 2007 10:25 AM
Jon Skeet [C# MVP]
Nik Coughlin <nrkn.***@gmail.com> wrote:
Show quote
> System.Console is really slow.  I wanted to make a retro text-only console
> application game (a roguelike), but I can't get decent performance out of
> it.  Does anyone know how to get decent performance out of it?  Is there
> some way of buffering the text before outputting it?  Here's my test code
> (slow!):
>
> Random r = new Random();
>
> Console.Clear( );
>
> while ( true ) {
>   for ( int y = 0; y < 20; y++ ) {
>     for ( int x = 0; x < 70; x++ ) {
>       Console.SetCursorPosition( x, y );
>       Console.ForegroundColor = (ConsoleColor) r.Next( 16 );
>       Console.Write( 'x' );
>     }
>   }
> }
>
> The only way I could get it to run at a decent speed was by using
> Console.WriteLine on each row, but that means I can't set the color for
> individual characters.

It's a lot smoother (on my box at least) if you only set the cursor
position at the start of the line, then do Console.Write 70 times.

From what I remember of rogue and the like, you don't need to redraw
the whole screen very often - I wouldn't have thought it would be a
problem.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Author
3 Feb 2007 10:45 AM
Nik Coughlin
Jon Skeet [C# MVP] wrote:
Show quote
> Nik Coughlin <nrkn.***@gmail.com> wrote:
>> System.Console is really slow.  I wanted to make a retro text-only
>> console application game (a roguelike), but I can't get decent
>> performance out of it.  Does anyone know how to get decent
>> performance out of it?  Is there some way of buffering the text
>> before outputting it?  Here's my test code (slow!):
>>
>> Random r = new Random();
>>
>> Console.Clear( );
>>
>> while ( true ) {
>>   for ( int y = 0; y < 20; y++ ) {
>>     for ( int x = 0; x < 70; x++ ) {
>>       Console.SetCursorPosition( x, y );
>>       Console.ForegroundColor = (ConsoleColor) r.Next( 16 );
>>       Console.Write( 'x' );
>>     }
>>   }
>> }
>>
>> The only way I could get it to run at a decent speed was by using
>> Console.WriteLine on each row, but that means I can't set the color
>> for individual characters.
>
> It's a lot smoother (on my box at least) if you only set the cursor
> position at the start of the line, then do Console.Write 70 times.

Yep, it's smoother but still nowhere near the performace of, well, doing it
any other way I've tried :)  SetCursorPosition and ForegroundColor seem to
be very slow.

> From what I remember of rogue and the like, you don't need to redraw
> the whole screen very often - I wouldn't have thought it would be a
> problem.

In traditional roguelikes the maps fit into one screen and the player moves
around the screen, so you're right, but I'm trying to have large, scrolling
maps.  I could do it in something else to get the speed, but damn it, .Net
should be able to do it and I'm stubborn :P
Author
7 Feb 2007 12:06 PM
Lasse_Vågsæther_Karlsen
Nik Coughlin wrote:
Show quote
> System.Console is really slow.  I wanted to make a retro text-only console
> application game (a roguelike), but I can't get decent performance out of
> it.  Does anyone know how to get decent performance out of it?  Is there
> some way of buffering the text before outputting it?  Here's my test code
> (slow!):
>
> Random r = new Random();
>
> Console.Clear( );
>
> while ( true ) {
>   for ( int y = 0; y < 20; y++ ) {
>     for ( int x = 0; x < 70; x++ ) {
>       Console.SetCursorPosition( x, y );
>       Console.ForegroundColor = (ConsoleColor) r.Next( 16 );
>       Console.Write( 'x' );
>     }
>   }
> }
>
> The only way I could get it to run at a decent speed was by using
> Console.WriteLine on each row, but that means I can't set the color for
> individual characters.
>
> As an aside note, I fired up the oldest programming IDE I could find
> (QuickBasic 4.5, ah the nostalgia) and tried this:
>
> CLS
>
> DO
>   FOR y% = 1 TO 20
>     FOR x% = 1 TO 70
>       LOCATE y%, x%
>       COLOR INT(RND * 16)
>       PRINT "x"
>     NEXT x%
>   NEXT y%
> LOOP
>
> It was blazingly fast.  Surely a modern framework like .Net can do fast
> console drawing, I must be missing something.
>
> Please tell me I don't have to use the Win32 API :)  I'm aiming to have it
> work in Mono too, so I want to stay in managed code.
>
>

Try to do minimal updates. Try making a off-screen copy of the map and
update this, keeping track og what portions are visible. Then, when you
need to update the screen, compare what you had on the screen previously
with what you need to have there now, and only update the portions that
have changed.

--
Lasse Vågsæther Karlsen
mailto:la***@vkarlsen.no

AddThis Social Bookmark Button