I am an amateur playing around with making simple games using Python and the Windows console through sys.stdout.write(). I am aware that this method of doing 'graphics' with printing ascii characters to the console is much slower than using the graphics card, but I have just been enjoying this simple project as I get my feet wet.

Does anyone have advice on ways to speed up the frame print time. Currently, I have every character on the console stored in a dictionary. The dictionary is iterated through, using the x,y coordinates as keys, and each character is appended to a String each frame that is printed to the console. With minimal game logic and 'graphics', I'm already down under 60 frames. I was wondering if it would be at all faster to use threading or multiprocessing to isolate printing the frame to the console (or converting my dictionary into a string) to speed up the time to each frame. I gave it a go myself, but printing to the console on a separate thread using 'threading' made no difference, and I couldn't get multiprocessing to work with a Queue to refresh each frame. If anyone has any advice on ways I could speed up my frame time, I'd appreciate it. If you got this far thank you for reading!

The Current Game Window showing FPS and Number of Ascii Characters in the bottom left

Here is a github link to my current code for reference:

The code is a little messy but the main drawing parts are at the end of the main loop and then the Ascii dict is modified in windowsConsoleGraphics.py

6 Replies 6

My guess is the main bottleneck is writing to IO. The way to speed things up is buffering frames correctly if you are not already. Instead of printing line by line, generate the whole frame/screen and write it at once. Second thing is to use asynchronously generate the frame and write to IO, or use different threads/processes for each. However, It's hard to see what's going wrong without a minimal code example.

This problem is reminiscent to the (old) problem of how to implement a visual editor on an old 24x80 terminal. The way they used to solve that was to (roughly speaking) work out what had changed between two frames and use ANSI / VT100 display codes to move the cursor around and update (only) the characters that have changed.

Multi-threading and multi-processing won't help. The actual bottleneck will be in the back end; i.e. the terminal emulator rendering and painting characters on the display. And avoiding redrawing characters that haven't actually changed will help with that.


Having said that, I'm not sure it is worth the effort to solve this problem. This kind of character display game has limited appeal ... these days. If I was you, I'd be looking for a more useful problem to solve. (And I'm not casting aspersions on games programming per se.)

import sys
import time

d = {'H': 10, 'E': 15, 'L': 20, 'L': 25, 'O': 30}

# Initialize an empty dictionary to store filtered items
res = {}

# Iterate through each key-value pair in dictionary
for key, val in d.items():

    # Check if value is within range
    if 10 <= val <= 40:  

        # Add matching items to new dictionary
        res[key] = val 
        sys.stdout.write(f'\rCountdown: {res} ')  
        sys.stdout.flush()
        time.sleep(1)


sys.stdout.write("\nTime's up!\n")  # Use double quotes to avoid conflict with the apostrophe
  1. try setting PYTHONUNBUFFERED environment variable into 1 before running python or pass -u to python itself. It might speed up things.

  2. os.write(1, "yourstringhere".encode())

On my machine, 100 iteratations with os.write() took 0.0001188750029541552seconds and sys.stdout.write() 2.1042011212557554e-05

However, not sure if os.write will bypass any console escape codes ..

Are you trying to implement this entirely yourself or looking for existing libraries that could help you? If it's the latter, then what you're doing is essentially reinventing the wheel. There exists software called ncurses which is packaged in the python standard library as curses. It basically allows you to treat the terminal like a canvas that you can paint strings on to. You can then "refresh" the screen when you are finished updating the screen. This should be much faster as it only requires that you update the bits of the screen that changed rather than recreating the entire screen in a single string.

As a bonus, curses can also allow you to react to individual keypresses (or lifts). Meaning you can react to user input immediately, rather than having to wait for them to press enter. In practice, this means you could have a game that has a WASD-style input to move an object around the screen.

I haven't looked at your code, but appending each character to a string is likely to cause lots of reallocation of memory and copying. If your console is, say 80x24 maybe you can allocate that many bytes in one go and then stuff your characters into a single pre-allocated buffer.

Your Reply

By clicking “Post Your Reply”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.