我有一个应用程序依赖于多个阻塞操作的超时信号。
例如:
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:我在main中启动线程如下:
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:我已经创建了一个更详细和准确的示例,说明我打算如何在线程中使用singals。 See the gist here
答案 0 :(得分:2)
您正在寻找的是看门狗。
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})
注意:代码未经过测试,可能会出现语法错误!
答案 1 :(得分:1)
这实现了.nav img:hover + ul li {
display: block;
}
,
在给定的class Terminator
到signal.SIG...
之后发送timeout=5
。多个不同的Threads Popen process
是可能的。
pid
这是工作量:
class Terminator(object):
class WObj():
def __init__(self, process, timeout=0, sig=signal.SIGABRT):
self.process = process
self.timeout = timeout
self.sig = sig
def __init__(self):
self.__queue = queue.Queue()
self.__t = Thread(target=self.__sigterm_thread, args=(self.__queue,))
self.__t.start()
time.sleep(0.1)
def __sigterm_thread(self, q):
w = {}
t = 0
while True:
time.sleep(0.1);
t += 1
try:
p = q.get_nowait()
if p.process == 0 and p.sig == signal.SIGTERM:
# Terminate sigterm_thread
return 1
if p.process.pid not in w:
if p.timeout > 0 and p.sig != signal.SIGABRT:
w[p.process.pid] = p
else:
if p.sig == signal.SIGABRT:
del (w[p.process.pid])
else:
w[p.process.pid].timeout = p.timeout
except queue.Empty:
pass
if t == 10:
for key in list(w.keys()):
p = w[key]
p.timeout -= 1
if p.timeout == 0:
""" A None value indicates that the process hasn't terminated yet. """
if p.process.poll() == None:
p.process.send_signal(p.sig)
del (w[p.process.pid])
t = 0
# end if t == 10
# end while True
def signal(self, process, timeout=0, sig=signal.SIGABRT):
self.__queue.put(self.WObj(process, timeout, sig))
time.sleep(0.1)
def close(self, process):
self.__queue.put(self.WObj(process, 0, signal.SIGABRT))
time.sleep(0.1)
def terminate(self):
while not self.__queue.empty():
trash = self.__queue.get()
if self.__t.is_alive():
self.__queue.put(self.WObj(0, 0, signal.SIGTERM))
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.__del__()
def __del__(self):
self.terminate()
使用Python测试:3.4.2和Python:2.7.9