elyonis
elyonis

Reputation: 36

Multiple Processes in Python

I am writing a program with an infinite while loop that runs a function which takes input from the user and then prints to the console. I would like to be able to do something along the lines of having a separate piece of code that continually checks the time as a background process and at a certain time, prints a message to the console and asks whether you'd like to quit the program or continue the while loop. I assume I'd need multithreading or something along the lines of that.

def main():
    while True:
        x = input("Write Something: ")
        print(x)

main()

Upvotes: 0

Views: 239

Answers (2)

unutbu
unutbu

Reputation: 879391

Here is an attempt using Tim Peters' suggestion to use threading.Timer:

import threading

check_done = False
def are_we_done_yet():
    global check_done
    print("quit now?")
    check_done = True
    t = threading.Timer(2.0, are_we_done_yet)
    t.daemon = True
    t.start()

t = threading.Timer(2.0, are_we_done_yet)
t.daemon = True
t.start()

while True:
    response = raw_input('>>> ')
    if check_done:
        if response.lower().startswith('y'): break
        check_done = False

One problem with the code above is that there is no way to distinguish input that the user intended for the >>> prompt from the user's response to the question quit now?.

If the user happened to be typing a sentence beginning with a y when the quit now? question pops up, then the user might unintentionally cause the program to quit.

So a cleaner solution might be to use a GUI:

import Tkinter as tk
import tkMessageBox
def are_we_done_yet():
    if tkMessageBox.askyesno(title="Quit", message="Quit now?",
                             default=tkMessageBox.NO):
        root.quit()
    root.after(2000, are_we_done_yet)

root = tk.Tk()
root.geometry('300x200')
entry = tk.Text(root)
entry.pack()
entry.focus()
root.after(2000, are_we_done_yet)
root.mainloop()

Upvotes: 1

Tim Peters
Tim Peters

Reputation: 70592

Threads are good for this, and the background thread will spend most of its time sleeping. Here's something you can start with. You'll have lots of problems eventually - comes with the territory ;-)

import threading

timetoquit = False
iolock = threading.Lock()

class Watcher(threading.Thread):
    def __init__(self, timeout):
        threading.Thread.__init__(self)
        self.timeout = timeout
        self.waiter = threading.Event()

    def run(self):
        global timetoquit
        while not timetoquit:
            self.waiter.wait(self.timeout)
            if timetoquit:
                return
            with iolock:
                i = raw_input("want to quit? ")
            if i.startswith("y") or i.startswith("Y"):
                timetoquit = True
            self.waiter.clear()

    # Unused in this example, but you may want it someday ;-)
    def cancel(self):
        global timetoquit
        timetoquit = True
        self.waiter.set()

# this Watcher will ask every 10 seconds
watch = Watcher(10)
watch.start()

while not timetoquit:
    # do stuff
    # put console interaction in `with iolock` to
    #   prevent the main program and the thread from
    #   messing with the console at the same time
    with iolock:
        if not timetoquit:
            whatever = raw_input("enter something ")
    # do stuff

Upvotes: 2

Related Questions