我想创建一个函数的多线程版本。我发现t.start()
返回None
,所以我必须使用队列。
我搜索了文档,但我不明白如何在我的例子中使用它。
这是功能:
def derivative(lst, var): # Example of lst = [1 + [3 * x]]
if len(lst) == 1:
return derive_solver(lst[0], var)
if lst[1] == '+':
return [derivative(lst[0], var), '+', derivative(lst[2], var)]
if lst[1] == '*':
return [[derivative(lst[0], var), '*', lst[2]], '+', [lst[0], '*', derivative(lst[2], var)]]
这是我尝试多线程的功能:
def derivative(lst, var): # Example of lst = [1 + [3 * x]]
if len(lst) == 1:
return derive_solver(lst[0], var)
if lst[1] == '+':
t1 = threading.Thread(target = derivative, args=(lst[0], var))
t2 = threading.Thread(target = derivative, args=(lst[2], var))
return [t1.start(), '+', t2.start()]
if lst[1] == '*':
t1 = threading.Thread(target = derivative, args=(lst[0], var))
t2 = threading.Thread(target = derivative, args=(lst[2], var))
return [[t1.start(), '*', lst[2]], '+', [lst[0], '*', t2.start()]]
问题是t1.start(
)不返回值...
你知道如何使用队列来解决这个问题吗?
谢谢!
答案 0 :(得分:4)
问题是
t1.start()
没有返回值...
当然不是。 t1
此时尚未完成。如果start
等待后台线程完成,那么首先绝对没有理由使用线程。
你需要进行设置,以便后台线程在某处发布他们的工作并发出信号告诉他们他们已经完成了,然后等到两个线程都向你发出信号。队列是一种方法。共享变量加上Condition
也是如此。或者,在这种情况下,只是一个共享变量加上join
线程。但是,我会用一种方式来展示一个队列,因为那是你要求的:
def enthread(target, args):
q = queue.Queue()
def wrapper():
q.put(target(*args))
t = threading.Thread(target=wrapper)
t.start()
return q
q1 = enthread(target = derivative, args=(lst[0], var))
q2 = enthread(target = derivative, args=(lst[2], var))
return [q1.get(), '+', q2.get()]
我所做的是创建一个队列,将其传递给后台线程的目标函数(包装真实的目标函数),并让后台线程将其结果放在队列中。然后,主线程可以等待队列。
请注意,这不是join
每个线程,这可能是个问题。但希望您能看到如何扩展代码以使其更加健壮。
另请注意,我们会在检查主题2之前明确等待主题1完成。在您无法完成所有结果之前无法执行任何操作的情况下,这很好。但是在许多应用程序中,您需要一个单个队列,因此您可以在结果进入时获取结果(如果您需要能够重建,请以某种方式标记值)原始订单)。
更好的解决方案是使用更高级别的抽象,如线程池或未来(或执行器,它将两个抽象合并为一个)。但是,值得了解这些部分是如何工作的,然后学习如何以简单的方式做事。因此,一旦您了解其原因,请阅读concurrent.futures
上的文档。
最后,假设你正在使用CPython或其他基于GIL的实现 - 你可能是 - 并且derive_solver
函数不是c扩展函数,明确设计用于完成大部分工作而不用GIL,这首先不是一个好主意。当你需要没有并行性的并发时(因为你的代码更简单,或者因为它的I / O绑定),线程很棒,但是当你真正尝试从多个内核中受益时,它们并不是'#39答案,因为当时只有一个线程可以运行解释器。如果您需要并行性,请使用multiprocessing
(或仅concurrent.futures.ProcessPoolExecutor
代替concurrent.futures.ThreadPoolExecutor
)。