#python
#python
Вопрос:
Я пытаюсь создать метод, который запускается по таймеру в фоновом режиме моего основного скрипта:
def hello_world(self):
print 'Hello!'
threading.Timer(2,hello_world).start()
if __name__ == "__main__":
try:
hello_world()
except KeyboardInterrupt:
print 'nGoodbye!'
Я получаю это сообщение, когда пытаюсь прервать мой скрипт с помощью клавиатуры:
Exception KeyboardInterrupt in <module 'threading' from '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py'> ignored
Как мне закрыть поток, чтобы я мог чисто выйти из своего приложения?
Ответ №1:
Чтобы немного уточнить ответ Aphex, основной поток не может перехватить сигнал KeyboardInterrupt, если у вас нет очень быстрых пальцев. Основной поток завершается почти немедленно! Попробуйте это:
import threading
def hello_world():
print 'Hello!'
threading.Timer(2,hello_world).start()
if __name__ == "__main__":
try:
hello_world()
except KeyboardInterrupt:
print 'nGoodbye!'
print "main thread exited"
В более общем плане, я бы не советовал использовать подобный таймер самостоятельного вызова только потому, что он создает много потоков. Просто создайте один поток и вызовите time.sleep
внутри него.
Однако, пока вы продолжаете работу основного потока, вы, кажется, можете перехватывать KeyboardInterrupt
внутри. Тогда хитрость заключается в том, чтобы сделать поток daemon
потоком, который завершается при завершении основного потока.
import threading
import time
def hello_world():
while(True):
print 'Hello!'
time.sleep(2)
if __name__ == "__main__":
hw_thread = threading.Thread(target = hello_world)
hw_thread.daemon = True
hw_thread.start()
try:
time.sleep(1000)
except KeyboardInterrupt:
print 'nGoodbye!'
Это завершается автоматически через 1000 секунд — вы могли бы увеличить это число еще больше, если хотите. Вы также могли бы использовать цикл занятости для повторения вызова режима ожидания, но я действительно не вижу в этом смысла.
Ответ №2:
Вам просто нужно установить Timer
поток как daemon
def hello_world(self):
print 'Hello!'
t = threading.Timer(2,hello_world)
t.daemon = True
t.start()
Это приведет к завершению работы при завершении основного потока, например, из-за KeyboardInterrupt
.
daemon
Настройка приводит к завершению всей программы, когда остаются только daemon
потоки.
Комментарии:
1. Мило! Это правильный ответ. Это единственный способ заставить потоки таймера не допускать, чтобы Ctrl C препятствовали выходу. И, в конечном счете… все таймеры должны включить это… потому что, даже если у вас есть только один… маловероятно, что вы хотите, чтобы Ctrl C отключил хотя бы один таймер …. без завершения основного потока.
Ответ №3:
Попробуйте повторно вызвать KeyboardInterrupt
исключение: http://effbot.org/zone/stupid-exceptions-keyboardinterrupt.htm
Это все еще может не сработать; скорее всего, вы сталкиваетесь с этим предостережением:
Потоки странно взаимодействуют с прерываниями: исключение KeyboardInterrupt будет получено произвольным потоком. (Когда модуль signal доступен, прерывания всегда передаются в основной поток.)
Короче говоря, вы не можете быть уверены, что KeyboardInterrupt
отправляется в ваш основной поток. Чтобы обойти это, вы можете заглянуть в signal
модуль.
Редактировать: Более элегантный способ отменить поток — иметь общую переменную, на которую смотрит поток, и завершает работу, если она становится false
. Затем, если вы хотите завершить поток из вашего основного потока, вы устанавливаете переменную в false
.
Комментарии:
1. Повторите свою правку: не является общей переменной. Используйте
threading.Event
для этого