10

この問題はほぼ解決しましたが、正しい方向に微調整する必要があると思います。

一定の時間が経過するユーザーが中断するまで、5 秒ごとに何かを実行したいと考えています(この場合、終了する前にループの反復を終了します)。

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()すると、スレッドが作業を終了するかどうかにかかわらず、ユーザーが Enter キーを押すまでブロックされます。私がやりたいことをする別のモジュールはありますか?

編集: Windows XP を使用しています。

4

3 に答える 3

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 
于 2012-08-01T12:45:35.307 に答える
2

これが私が問題を解決した方法です。私は実際には下位レベルのモジュールに移動したくなかったのでthread、ユーザーが CTRL-C を使用してプログラムを正常に終了させて​​くれることに満足していると判断しました。

目的を変更する方法が原因で、少し面倒です。つまり、 CTRL-C を必要とするKeyboardInterruptコードに実際に埋め込むことはできませんただし、私の目的には問題ありません。

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()
于 2012-08-01T13:31:44.597 に答える
1

注: Windows XP を使用しているとあなたが言う前にこの回答を書いたので、役に立ちません—<a href="http://docs.python.org/library/select.html#module- select" rel="nofollow">selectは、Windows のソケットでのみ機能します。答えは他の人にとってはまだ役に立つと思うので、ここに残しておきます。


これは、デバッグが必要になると確信しているため、サンプルコードを書くよりも少し複雑になりますが、次のように問題にアプローチする可能性があります。

5 秒のタイムアウトを指定してselect、ループで Waiting on を使用します。sys.stdin返されるたびに、入力が存在しない場合は、スレッドを再度開始し (最後のスレッドが実際に実行を終了したかどうかを確認するなど)、ループを続行します。入力があれば、ループを終了します。

入力が存在することを示す場合select、それを割り込みのフラットアウトreadと見なすか、入力内にあると見なして、それが有効な割り込みを構成するかどうかを評価します。そうでない場合は、さらなる入力を保留して割り込みを完了するためにバッファーに入れることができます。中断の場合は、スレッドが作業を完了するのを待ちます。

于 2012-08-01T12:09:22.290 に答える