我有一个应用程序,它依赖于一些阻塞操作的超时信号。
例如:
def wait_timeout(signum, frame):
raise Exception("timeout")
signal.signal(signal.SIGALRM, wait_timeout)
signal.setitimer(signal.ITIMER_REAL, 5)
try:
while true:
print("zzz")
sleep(1)
except Exception as e:
# timeout
print("Time's up")
现在我已经使用相同的方法实现了多线程,但是对于所有线程我都得到了ValueError: signal only works in main thread
。
我假设信号超时的方法不适用于线程。
不幸的是我不能使用这样的东西:
timeout = 5
start = time.time()
while true:
print("zzz")
sleep(1)
if time.time() <= start+timeout:
print("Time's up)
break
由于 while 循环中的操作可能会阻塞并可能永远持续下去,因此循环可能永远不会到达 if 子句。
问:如何在线程中实现超时,就像我以前对信号所做的那样?
编辑:我遇到了 this blog post ,显示了与 python 中的 JavaScript 中的 setTimeout()
类似的解决方案。我认为这可能是一个可能的解决方案,但我真的不确定如何使用它。
edit2:我按如下方式在主线程中启动线程:
p = Popen(["tool", "--param", arg], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
t = Thread(target=process_thread, daemon=True, args=(p,arg1,arg2))
t.start()
process_thread
函数通过执行以下操作处理 tool
的标准输出:
for line in p.stdout:
# process line of the processes stdout
这个过程可能需要很长时间,例如一旦 tool
没有产生任何输出。我只需要 tool
的输出,比方说 5 秒,因此需要在特定超时后中断 for 循环。
这就是我使用信号的原因,但显然它们在线程中不起作用。
edit3: 我已经创建了一个更详尽和准确的示例来说明我打算如何在线程中使用信号。 See the gist here
最佳答案
您正在寻找的是一个看门狗。
def watchdog(queue):
while True:
watch = queue.get()
time.sleep(watch.seconds)
try:
watch = queue.get_nowait()
# No except, got queue message,
# do noting wait for next watch
except queue.Empty:
os.kill(watch.pid, signal.SIGKILL)
def workload_thread(queue):
pid = os.getpid()
queue.put({'pid':pid, 'seconds':5})
# do your work
# Test Watchdog
# time.sleep(6)
queue.put({'pid':pid, 'done':True})
注意:代码未经测试,可能存在语法错误!
关于python - python线程中超时信号的替代方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42647772/