Python - 直到按键或超时才做某事

时间:2012-08-01 11:49:01

标签: python multithreading timeout keypress wait

我几乎解决了这个问题,但我认为我需要朝着正确的方向努力。

我希望每五秒钟做一次,直到 经过一段时间用户中断它(在这种情况下,它完成了循环的迭代)在完成之前)。

import time
import threading

def do_something():
    T0 = time.clock()
    while (time.clock() - T0) < 60 and not e.isSet(): #as long as 60s haven't elapsed
                                                      #and the flag is not set
        #here do a bunch of stuff
        time.sleep(5)

thread = threading.Thread(target=do_something, args=())
thread.start()
e = threading.Event()

while thread.isAlive():
    #here I want the main thread to wait for a keypress and, if it receives it,
    #set the event e, which will cause the thread to finish its work.

我无法弄清楚如何使最后一行工作。在循环内使用raw_input()将阻塞,直到用户点击输入线程是否完成其工作。还有另一个模块可以做我想要的吗?

编辑:我使用的是Windows XP。

3 个答案:

答案 0 :(得分:2)

您可以使用thread.interrupt_main()


示例:

import thread
import time
import threading

e = threading.Event()

def main():
    thread.start_new_thread(wait_for_input, tuple())
    thread.start_new_thread(do_something, tuple())

def wait_for_input():
    raw_input()
    e.set()

def do_something():
    T0 = time.clock()
    while (time.clock() - T0) < 60 and not e.isSet(): #as long as 60s haven't elapsed
                                                      #and the flag is not set
        #here do a bunch of stuff
        time.sleep(5)
    thread.interrupt_main() # kill the raw_input thread

try:
    thread.start_new_thread(main, tuple())
    while 1:
        time.sleep(0.1) 
except KeyboardInterrupt:
    pass 

答案 1 :(得分:2)

以下是我解决问题的方法。我真的不想转移到较低级别的thread模块,我觉得我很高兴用户使用CTRL-C来使程序正常退出。

由于它重新定位KeyboardInterrupt的方式,这有点像一个小讽,这意味着它无法真正嵌入到所需的代码中需要CTRL-C成为一个不合适的退出。但是我的目的没问题。

import time
import threading

def do_something():
    T0 = time.clock()
    while (time.clock() - T0) < 60 and not e.isSet(): #as long as 60s haven't elapsed
                                                      #and the flag is not set
        #here do a bunch of stuff
        time.sleep(5)

thread = threading.Thread(target=do_something, args=())
e = threading.Event()
thread.start()

print 'Press CTRL-C to interrupt'
while thread.isAlive():
    try: time.sleep(1) #wait 1 second, then go back and ask if thread is still alive
    except KeyboardInterrupt: #if ctrl-C is pressed within that second,
                              #catch the KeyboardInterrupt exception
        e.set() #set the flag that will kill the thread when it has finished
        print 'Exiting...'
        thread.join() #wait for the thread to finish

更新:事实证明使用GUI按钮要简单得多。以下代码不涉及KeyboardInterrupt

稍微不完整的重新调整用途
import time
import threading
import Tkinter as Tk

def do_something():
    T0 = time.clock()
    while (time.clock() - T0) < 60 and not e.isSet(): #as long as 60s haven't elapsed
                                                      #and the flag is not set
        #here do a bunch of stuff
        time.sleep(5)

def _quit():
    print 'Exiting...'
    e.set()
    thread.join() #wait for the thread to finish
    root.quit()
    root.destroy()

root = Tk.Tk()
QuitButton = Tk.Button(master=root, text='Quit', command=_quit) #the quit button
QuitButton.pack(side=Tk.BOTTOM)

thread = threading.Thread(target=do_something, args=())
e = threading.Event()
thread.start()
root.mainloop()

答案 2 :(得分:1)

注意:我在您提到使用Windows XP之前写过这个答案,因此它无法帮助您 - select only works on sockets under Windows。我认为答案对其他人来说仍然有用,所以我会留在这里。


这比编写示例代码要复杂得多,因为我确定它需要一些调试,但我可能会这样解决问题:

我在循环中使用select,等待sys.stdin,超时为5秒。每次返回时,如果没有输入,我会再次启动线程(可能检查最后一个线程是否已经完成运行),然后继续循环。如果输入存在,我将退出循环。

select表示存在输入时,我可以将其视为输入中的中断或read,并评估它是否构成有效中断 - 如果不是,我可以缓冲它等待进一步输入以完成中断。如果是中断,我会等待线程完成工作。