我在Windows上使用Python 3.5.2。
我想运行一个python脚本,但保证它不会超过 N 秒。如果 超过 N 秒,则应引发异常,程序应退出。最初我曾想过我可以在开始时启动一个线程,在抛出异常之前等待 N 秒,但这只会设法向定时器线程抛出异常,而不是父线程。例如:
import threading
import time
def may_take_a_long_time(name, wait_time):
print("{} started...".format(name))
time.sleep(wait_time)
print("{} finished!.".format(name))
def kill():
time.sleep(3)
raise TimeoutError("No more time!")
kill_thread = threading.Thread(target=kill)
kill_thread.start()
may_take_a_long_time("A", 2)
may_take_a_long_time("B", 2)
may_take_a_long_time("C", 2)
may_take_a_long_time("D", 2)
输出:
A started...
A finished!.
B started...
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Program Files\Python35\lib\threading.py", line 914, in _bootstrap_inner
self.run()
File "C:\Program Files\Python35\lib\threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "timeout.py", line 11, in kill
raise TimeoutError("No more time!")
TimeoutError: No more time!
B finished!.
C started...
C finished!.
D started...
D finished!.
这甚至可以远程实现吗?我意识到我可以做这样的事情:
import threading
import time
def may_take_a_long_time(name, wait_time, thread):
if not thread.is_alive():
return
print("{} started...".format(name))
time.sleep(wait_time)
print("{} finished!.".format(name))
def kill():
time.sleep(3)
raise TimeoutError("No more time!")
kill_thread = threading.Thread(target=kill)
kill_thread.start()
may_take_a_long_time("A", 2, kill_thread)
may_take_a_long_time("B", 2, kill_thread)
may_take_a_long_time("C", 2, kill_thread)
may_take_a_long_time("D", 2, kill_thread)
但是,如果调用may_take_a_long_time("B", 60, kill_thread)
,则此方法失败。
所以我猜我的TL; DR问题是,对主线程本身设置时间限制的最佳方法是什么?
答案 0 :(得分:6)
您可以使用_thread.interrupt_main
(此模块在Python 2.7中称为thread
):
import time, threading, _thread
def long_running():
while True:
print('Hello')
def stopper(sec):
time.sleep(sec)
print('Exiting...')
_thread.interrupt_main()
threading.Thread(target = stopper, args = (2, )).start()
long_running()
答案 1 :(得分:2)
如果父线程是根线程,您可能想尝试os._exit(0)
。
import os
import threading
import time
def may_take_a_long_time(name, wait_time):
print("{} started...".format(name))
time.sleep(wait_time)
print("{} finished!.".format(name))
def kill():
time.sleep(3)
os._exit(0)
kill_thread = threading.Thread(target=kill)
kill_thread.start()
may_take_a_long_time("A", 2)
may_take_a_long_time("B", 2)
may_take_a_long_time("C", 2)
may_take_a_long_time("D", 2)
答案 2 :(得分:-1)
最简洁的方法是拥有一个父线程定期检查的队列。如果孩子想要杀死父母,它会向队列发送一条消息(例如“DIE”)。父进程检查队列,如果看到消息,它就死掉。
q = queue.Queue()
bc = queue.Queue() # backchannel
def worker():
while True:
key = q.get()
try:
process_key(key)
except ValueError as e:
bc.put('DIE')
q.task_done()
# Start the threads
for i in range(args.threads):
threading.Thread(target=worker, daemon=True).start()
for obj in object_farm():
q.put(obj)
try:
back = bc.get(block=False)
except queue.Empty:
pass
else:
print("Data received on backchannel:",back)
if back=='DIE':
raise RuntimeError("time to die")