Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 额外线程装饰器_Python_Multithreading_Decorator - Fatal编程技术网

Python 额外线程装饰器

Python 额外线程装饰器,python,multithreading,decorator,Python,Multithreading,Decorator,我试图在gui后面自动化任务。我的gui有多个按钮用于启动某些功能,一个按钮用于停止当前正在运行的任何功能。当一个功能正在运行时,除“取消”按钮外的所有按钮均灰显。我需要额外的线程,以便我的gui在运行冗长的函数时仍能响应 现在我想实现一个装饰器来装饰这些功能。此装饰程序应在单独的线程中运行该函数。当用户按下cancel按钮时,这个额外线程中的函数应该会收到某种停止信号,修饰后的函数可以使用该信号停止当前任务并退出 我知道可以为每个函数实现threading.Thread类型的类,并将当前函数作

我试图在gui后面自动化任务。我的gui有多个按钮用于启动某些功能,一个按钮用于停止当前正在运行的任何功能。当一个功能正在运行时,除“取消”按钮外的所有按钮均灰显。我需要额外的线程,以便我的gui在运行冗长的函数时仍能响应

现在我想实现一个装饰器来装饰这些功能。此装饰程序应在单独的线程中运行该函数。当用户按下cancel按钮时,这个额外线程中的函数应该会收到某种停止信号,修饰后的函数可以使用该信号停止当前任务并退出

我知道可以为每个函数实现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()
但如果我创建类,它将如下所示:

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:

我的新代码,在Salomonderosi的伟大示例之后:

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

装饰程序需要创建一种与线程联合的方法。在本例中,每个应该作为线程运行的函数必须首先具有
queue
参数。此
队列
用于与线程通信。在本例中,可以将任何内容放入队列以停止线程,因为函数仅检查值是否可以从队列中取出

使用
queue.get(False)
函数尝试从队列中获取元素(无需等待)。如果没有元素(队列为空),则引发异常。否则,队列中有东西,线程被告知退出

要告诉线程退出,必须在线程队列中放入一些内容。这是通过
queue.put(“stop”)
完成的。在这种情况下,争论并不重要

这意味着,您必须定期检查队列中是否有内容并对其作出反应(在本例中,只需停止处理)

#/usr/bin/env python
#-*-编码:utf-8-*-
从线程导入线程
从functools导入包装
从时间上导入睡眠
尝试:
将队列作为队列导入
除恐怖外:
将队列作为队列导入
def运行异步(func):
@包装(func)
定义异步函数(*args,**kwargs):
queue=queue.queue()
t=Thread(target=func,args=(queue,)+args,kwargs=kwargs)
t、 开始()
返回队列
返回异步函数
@异步运行
def do_其他事项(队列):
尽管如此:
睡眠(1)
打印(“做其他事情”)
#检查队列中是否有内容,如果有则返回
尝试:
queue.get(False)
队列除外。空:
通过
其他:
打印(“被告知退出”)
返回
@异步运行
def打印数据(队列):
打印(“开始打印某些数据”)
睡眠(2)
尝试:
queue.get(False)
队列除外。空:
通过
其他:
打印(“被告知退出”)
返回
打印('print_somedata:2秒通过')
睡眠(2)
尝试:
queue.get(False)
队列除外。空:
通过
其他:
打印(“被告知退出”)
返回
print('print_somedata:又过了2秒')
睡眠(2)
尝试:
queue.get(False)
队列除外。空:
通过
其他:
打印(“被告知退出”)
返回
打印(“已完成打印\u某些数据”)
def test():
线程=列表()
#此时线程被创建并立即启动
append(print_somedata())
打印('返回主')
#此时线程被创建并立即启动
append(print_somedata())
打印('返回主')
#此时线程被创建并立即启动
threads.append(do\u something\u else())
打印('返回主')
#此时线程被创建并立即启动
threads.append(do\u something\u else())
打印('返回主')
打印(“在主屏幕中稍等一下”)
sleep(1)#取消对wait here的注释以快速停止线程;)
#您不必显式地等待,因为线程已经存在
#跑步。这只是一个演示如何与用户交互的示例
#线
对于队列,线程中的t:
打印(“告诉线程停止:%s”,t)
queue.put('stop')
#t、 加入
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
测试()

为什么类
线程化。线程
不是一个优雅的解决方案?@AlexHall:我不想杀死它,我想让函数自己处理停止信号并退出。@julivico:因为我必须编写5个类,而不是5个函数和一个装饰器。除了内部的run函数外,这些类是相同的。我知道我可以继承其中的一个,并更改其中每一个的run函数。对于这个看似简单的任务来说,它似乎太复杂了。它并不更复杂,事实上它更简单,不仅如此,它更容易阅读和维护。你陷入了代码越少越好的陷阱。这不是我的意思。我不想要多个任务,而是等待所有的任务。我想要一个任务,而不是等待,并且可以选择向此任务中运行的函数发送停止请求。@Stefan您不必等待,只需调用
print\u somedata()
并继续。他刚刚向你展示了如果你需要的话,你可以如何访问这个线程