【发布时间】:2016-09-09 07:02:33
【问题描述】:
我正在尝试在 gui 后面自动执行任务。我的 gui 有多个按钮可以启动某些功能,一个按钮可以停止当前正在运行的任何功能。当一个功能正在运行时,除“取消”按钮外的所有按钮都显示为灰色。我需要额外的线程,以便我的 gui 在冗长的函数运行时仍然响应。
现在我想实现一个装饰器来装饰这些功能。这个装饰器应该在一个单独的线程中运行这个函数。当用户按下取消按钮时,这个额外线程中的函数应该接收到某种停止信号,装饰函数可以使用该信号来停止其当前任务并退出。
我知道可以为每个函数实现一个 threading.Thread 类型的类并将当前函数插入为“def run(self):”,但这似乎不是一个优雅的解决方案。
有办法吗?对我来说,这似乎是一个常见问题,但除了将函数编写为类并将它们作为单独的线程运行之外,我还没有通过 Google 找到任何解决方案。
编辑 1:
让我添加一些例子。现在我的函数看起来像这样:
def function1:
function_code
但如果我创建类,它会是这样的:
class class1(threading.Thread):
stopper = None
def __init__(self):
init_code
def run(self):
function_code
def function1:
t = class1()
t.stopper = some_stop_condition
t.run()
第二个代码要长得多,每个按钮都需要一个类和一个函数。它看起来要复杂得多,我希望它是不必要的。
是我错了还是我做错了什么?
编辑2:
我的新准则,以 salomonderossi 为榜样:
def run_async(func):
@functools.wraps(func)
def async_func(*args, **kwargs):
queue = Queue.Queue()
t = threading.Thread(target=func, args=(queue,) + args, kwargs=kwargs)
t.start()
return queue, t
return async_func
# @layout_decorators.runInSeparateThread()
@run_async
def test2(myQueue):
print "executing test2"
import time
for k in range(6):
print k
try:
myQueue.get(False)
except Queue.Empty:
print "cancelled"
return
time.sleep(1)
def test22():
print "executing test22"
global globalQueue
globalQueue, t = test2()
if __name__ == "__main__":
import time
print "\n\n"
test22()
time.sleep(2)
globalQueue.put("stop")
但它会在第一时间停止线程。即使我删除了最后一行(我认为它会停止线程),我的输出也是
executing test22
executing test2
0
cancelled
【问题讨论】:
-
为什么
threading.Thread类不是一个优雅的解决方案? -
@AlexHall:我不想杀死它,我希望函数处理停止信号并自行退出。
-
@julivico:因为我必须编写 5 个类而不是 5 个函数和一个装饰器。除了里面的 run-function 之外,这些类是相同的。我知道我可以从其中一个继承并更改每个的运行功能。对于这个看似简单的任务来说似乎还是太复杂了。
-
它并不复杂,实际上它更简单,不仅如此,它更易于阅读和维护。你陷入了代码越少越好的陷阱。
标签: python multithreading decorator