下面的代码按照我期望的方式工作,即:
为了做到这一点,我不得不把1秒的睡眠分解成50毫秒的块来检查一个标志。
是否有一种在线程中睡眠一段时间(例如1秒),但会被某些标志或信号打断的方式?
try:
for i in xrange(8):
print "i=%d" % i
for _ in xrange(20):
time.sleep(0.05)
if not self.running:
raise GracefulShutdown
except GracefulShutdown:
print "ernie exiting" 我宁愿这样做,并在线程中以某种方式导致GracefulShutdown异常:
try:
for i in xrange(8):
print "i=%d" % i
time.sleep(1)
# somehow allow another thread to raise GracefulShutdown
# during the sleep() call
except GracefulShutdown:
print "ernie exiting" 全程序;
from PySide import QtCore, QtGui
from PySide.QtGui import QApplication
import sys
import signal
import time
class GracefulShutdown(Exception):
pass
class Ernie(QtCore.QThread):
def __init__(self):
super(Ernie, self).__init__()
self.running = True
def run(self):
try:
for i in xrange(8):
print "i=%d" % i
for _ in xrange(20):
time.sleep(0.05)
if not self.running:
raise GracefulShutdown
except GracefulShutdown:
print "ernie exiting"
def shutdown(self):
print "ernie received request to shutdown"
self.running = False
class Bert(object):
def __init__(self, argv):
self.app = QApplication(argv)
self.app.quitOnLastWindowClosed = False
def show(self):
widg = QtGui.QWidget()
widg.resize(250, 150)
widg.setWindowTitle('Simple')
widg.show()
self.widg = widg
return widg
def shutdown(self):
print "bert exiting"
self.widg.close()
def start(self):
# return control to the Python interpreter briefly every 100 msec
timer = QtCore.QTimer()
timer.start(100)
timer.timeout.connect(lambda: None)
return self.app.exec_()
def handleInterrupts(*actors):
def handler(sig, frame):
print "caught interrupt"
for actor in actors:
actor.shutdown()
signal.signal(signal.SIGINT, handler)
bert = Bert(sys.argv)
gratuitousWidget = bert.show()
ernie = Ernie()
ernie.start()
handleInterrupts(bert, ernie)
retval = bert.start()
print "bert finished"
while not ernie.wait(100):
# return control to the Python interpreter briefly every 100 msec
pass
print "ernie finished"
sys.exit(retval)发布于 2014-07-07 18:34:16
我不知道它是怎样的毕不过,但它起作用了。只需使用队列并使用带超时的阻塞get。见下面的例子:
import threading
import Queue
import time
q = Queue.Queue()
def workit():
for i in range(10):
try:
q.get(timeout=1)
print '%s: Was interrupted' % time.time()
break
except Queue.Empty:
print '%s: One second passed' % time.time()
th = threading.Thread(target=workit)
th.start()
time.sleep(3.2)
q.put(None)发布于 2014-07-07 19:40:19
通常,SIGINT会中断time.sleep调用,但是Python只允许应用程序的主线程接收信号,因此不能在这里使用。如果可能的话,我建议避免使用time.sleep,而是使用QTimer。
from PySide import QtCore, QtGui
from PySide.QtCore import QTimer
from PySide.QtGui import QApplication
import sys
import signal
from functools import partial
class Ernie(QtCore.QThread):
def __init__(self):
super(Ernie, self).__init__()
def do_print(self, cur_num, max_num):
print "i=%d" % cur_num
cur_num += 1
if cur_num < max_num:
func = partial(self.do_print, cur_num, max_num)
QTimer.singleShot(1000, func)
else:
self.exit()
def run(self):
self.do_print(0, 8)
self.exec_() # QTimer requires the event loop for the thread be running.
print "ernie exiting"
class Bert(object):
def __init__(self, argv):
self.app = QApplication(argv)
self.app.quitOnLastWindowClosed = False
def show(self):
widg = QtGui.QWidget()
widg.resize(250, 150)
widg.setWindowTitle('Simple')
widg.show()
self.widg = widg
return widg
def shutdown(self):
print "bert exiting"
self.widg.close()
def start(self):
# return control to the Python interpreter briefly every 100 msec
timer = QtCore.QTimer()
timer.start(100)
timer.timeout.connect(lambda: None)
return self.app.exec_()
def handleInterrupts(*actors):
def handler(sig, frame):
print "caught interrupt"
for actor in actors:
actor.shutdown()
signal.signal(signal.SIGINT, handler)
bert = Bert(sys.argv)
gratuitousWidget = bert.show()
ernie = Ernie()
ernie.start()
handleInterrupts(bert)
retval = bert.start()
print "bert finished"
ernie.exit()
while not ernie.wait(100):
# return control to the Python interpreter briefly every 100 msec
pass
print "ernie finished"
sys.exit(retval)我们没有让run()方法使用time.sleep运行for循环,而是在线程中启动一个事件循环,并使用QTimer在一个设置的间隔内执行所需的打印。这样,只要我们希望线程关闭,我们就可以调用bernie.exit(),这将导致bernie'的事件循环立即关闭。
编辑:
这里有一种实现相同想法的替代方法,即至少要隐藏一些复杂性,允许原始for循环保持原样:
def coroutine(func):
def wrapper(*args, **kwargs):
def execute(gen):
try:
op = gen.next() # run func until a yield is hit
# Determine when to resume execution of the coroutine.
# If func didn't yield anything, schedule it to run again
# immediately by setting timeout to 0.
timeout = op or 0
func = partial(execute, gen)
QTimer.singleShot(timeout, func) # This schedules execute to run until the next yield after `timeout` milliseconds.
except StopIteration:
return
gen = func(*args, **kwargs) # Get a generator object for the decorated function.
execute(gen)
return wrapper
def async_sleep(timeout):
""" When yielded inside a coroutine, triggers a `timeout` length sleep. """
return timeout
class Ernie(QtCore.QThread):
def __init__(self):
super(Ernie, self).__init__()
self.cur_num = 0
self.max_num = 8
@coroutine
def do_print(self):
for i in range(8):
print "i=%d" % i
yield async_sleep(1000) # This could also just be yield 1000
self.exit()
def run(self):
self.do_print() # Schedules do_print to run once self.exec_() is run.
self.exec_()
print "ernie exiting" coroutine允许修饰函数在任何时候出现Qt事件循环时将控制权还给Qt事件循环,然后继续执行修饰的方法。当然,这实际上只是从我最初的示例中转移了复杂性,但它确实将其隐藏在线程中的实际工作之外。
的工作方式:
这种方法的灵感来源于异步库(如龙卷风和异步模块)中的协同实现。虽然我没有试着想出像那样强大的东西,但想法是一样的。我们希望能够中断的方法被实现为生成器,并使用一个装饰器来修饰,它知道如何调用和接收生成器的响应,从而允许正确地暂停/恢复生成器。调用do_print的流程基本上如下:
do_print()是从run调用的。这实际上导致调用coroutine.wrapper。wrapper调用真实的do_print,它返回生成器对象。它将该对象传递给execute。execute对生成器对象调用next。这将导致do_print运行,直到yield被击中。然后暂停do_print的执行。execute安排do_print继续执行。它首先通过使用运行的上一次迭代中的yielded值来确定何时调度,或者默认为0(该值计划立即恢复执行)。它调用QTimer.singleShot来调度自己,在timeout毫秒内再次运行,使用partial,这样它也可以传递生成器对象。do_print停止屈服,调用self.exit()并返回,此时引发StopIteration,而coroutine装饰器只是返回而不是调度另一个execute调用。发布于 2014-07-07 18:32:34
我的本能反应是用os.kill发出信号,但是只有主线程才能接收信号,所以厄尼不能被这样打断。文档建议使用锁。
我在这里的想法是创建一个锁,只有在杀死厄尼的时候才能访问它。主线程创建了Bert和Ernie之后,创建并锁定了一个锁文件。然后,厄尼将花整整一秒的时间来尝试获得锁,而不是睡上一秒。一旦程序关闭,您可以释放锁,厄尼将立即得到;这告诉厄尼,是时候关闭。
由于您不能以我们希望的方式集成信号和线程,下面是另一篇关于线程锁定超时的文章:
我不能告诉你们Pythonic这个解决方案是怎样的,因为我仍然在试图弄清楚Pythonic到底意味着什么。一旦您开始引入线程,优雅的代码在任何情况下都会变得越来越难编写。
https://stackoverflow.com/questions/24617131
复制相似问题