简体   繁体   中英

Python Curses: Exiting a program fast

What is the best way to quickly exit a Python program with an infinite loop that uses curses module?

I've tried adding nodelay() method coupled with this at the end of the loop:

if screen.getch() == ord('q'):
    break

However, it takes 2-3 seconds to make all the function calls on one iteration of the loop. And because of the application, it doesn't make sense to run the loop more often than every 5 second. This means that in order for my way of exiting the program to work, I sometimes have to press and hold 'q' for 2-8 seconds.

My code looks like this:

import curses
import time

def main(screen):
    refresh_rate = 5
    screen.nodelay(1)

    # Infinite loop. Displays information and updates it 
    # every (refresh_rate) # of seconds

    while True:

        # Makes several http requests 
        # and passes responses through multiple functions

        # Escape infinite loop
        if screen.getch() == ord('q'):
            break

        # Wait before going through the loop again
        time.sleep(refresh_rate)

if __name__ == "__main__":
    curses.wrapper(main)

My other solution was to replace while True with:

loop = 1
while loop:

    #Loop code

if screen.getch() == ord('q'):
    loop = -1

This way, there is no need to press and hold 'q' to exit the program. But it can still take up to 8 seconds to exit after pressing 'q' once.

For obvious reasons, this doesn't seem to be the best way of exiting the program. I am pretty sure there should be a better (faster) solution.

Other than that, the program works fine. It's 2 files with more than 300 lines, so I am posting just the relevant parts of the code with my attempted solutions.

What's probably happening is that your 'q' is coming in between the getch() and the sleep calls. Given that getch() takes a fraction of a second to execute and sleep locks the program for 5 seconds, it's very likely that any time you press a key you're going to wait.

The easiest way to exit any python script is to press Ctrl-C - it spawns a KeyBoardInterrupt exception that can be handled like:

try:
while True:
    do_something()
except KeyboardInterrupt:
    pass

Granted, if this is meant to be a user-facing application, that might not be sufficient. But it's also unlikely that any production application would operate without a full event loop and a UI that would allow them to exit.

Last, if you want another way of doing what you're already doing, you can use:

import sys
sys.stdin.read(1)

To read 1 bye of user input at a time. I'd go for the Ctrl-C route, if I were you.

Given that you have nodelay already, the usual approach is to use napms with a small (20-50 milliseconds) time, and addressing your 5-seconds goal, to run the functions after several (10-25) repetitions of the getch/napms loop.

Mixing curses and standard I/O doesn't really work well unless you take care to flush things when switching between the two.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM