在 python 中使用 thread.start() 返回值(使用队列)

Mat*_*teo 2 python queue multithreading

我想创建一个函数的多线程版本。我发现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)]]
Run Code Online (Sandbox Code Playgroud)

这是我尝试多线程该功能:

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()]] 
Run Code Online (Sandbox Code Playgroud)

问题是t1.start() 不返回值...

你知道如何使用队列解决这个问题吗?

谢谢!

aba*_*ert 5

问题是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()]
Run Code Online (Sandbox Code Playgroud)

我所做的是创建一个队列,将它传递给后台线程的目标函数(它包装了真正的目标函数),然后让后台线程将其结果放在队列中。然后,主线程可以在队列中等待。

请注意,这不是join每个线程,这可能是一个问题。但希望您能看到如何扩展代码以使其更健壮。

另请注意,在检查线程 2 之前,我们明确地等待线程 1 完成。在获得所有结果之前您无法执行任何操作的情况下,这很好。但是,在许多应用中,你会希望有一个单一的队列,这样你就可以拿起的结果,因为他们进来(如果你需要能够重建原来的顺序标注在某些方面的数值)。


更好的解决方案是使用更高级别的抽象,例如线程池或未来(或执行器,将两个抽象结合为一个)。但值得先了解这些部分是如何工作的,然后学习如何以简单的方式做事。所以,一旦你理解了为什么会这样,就去阅读 上的文档concurrent.futures


最后,假设您正在使用 CPython 或其他基于 GIL 的实现(您可能是这样的)并且该derive_solver函数不是一个 C 扩展函数,明确设计用于在没有 GIL 的情况下完成大部分工作,这不会是一个首先是个好主意。当您需要没有并行性的并发性时(因为您的代码更简单,或者因为它受 I/O 限制),线程非常有用,但是当您真正尝试从多个内核中受益时,它们不是答案,因为只有一个线程此时可以运行解释器。如果需要并行性,请使用multiprocessing(或仅concurrent.futures.ProcessPoolExecutor代替concurrent.futures.ThreadPoolExecutor)。