python - 在 Python 中处理线程连接的正确方法

标签 python multithreading join spawn

所以我编写了一个工具,它获取项目列表,将其拆分为给定数量的列表(比如 10 个),然后获取这 10 个列表并产生 10 个线程,“EvaluationThreads”(扩展 threading.thread) ,并且这些线程中的每一个都会评估它们提供的评估内容。当我启动每个线程时,我将它们全部放入一个列表中,并且在生成它们之后我有以下代码:

for th in threadList:
    th.join()
    someTotal = th.resultsAttribute

这就是我处理等待所有线程完成并收集它们的信息的方式。虽然这是一种等待一切完成然后收集结果的工作方式,但我觉得必须有一种更优雅的方式来做到这一点,因为这些线程可以很好地在不同时间完成,如果第一个开始的线程最后完成所有那些较早完成的必须等待该线程完成才能加入。有没有办法获取这些线程的信息并在它们完成时加入它们,而不是按照它们开始的顺序加入?我最初认为我会在线程中使用某种回调或其他东西,但我不确定是否有更可接受的解决方案。

感谢您的帮助。

编辑:澄清一下,我的评估函数不受 CPU 限制,我也没有尝试在线程之间分发文档以尽快完成它,每个线程都有固定的偶数作业。

最佳答案

对于您的主要问题:

如果您正在做比这更复杂的事情——或者,特别是,如果您重复这样做——您可能需要一个“线程组”类。有几十个是预制的,但如果您不喜欢其中任何一个,自己写一个就很简单了。

然后,代替这个:

threadList = []
for argchunk in splitIntoChunks(values, 10):
  threadList.append(threading.Thread(target=myThreadFunc, args=argchunk))
...
someTotal = 0
for th in threadList:
  th.join()
  someTotal += th.resultsAttribute

你可以这样做:

threadGroup = ThreadGroup.ThreadGroup()
for argchunk in splitIntoChunks(values, 10):
  threadGroup.newThread(myThreadFunc, argchunk)
threadGroup.join()
someTotal = sum(th.resultsAttribute for th in threadGroup)

或者,也许更好,一个完整的线程池库,所以你可以这样做:

pool = ThreadPool(10)
for argchunk in splitIntoChunks(values, 100):
  pool.putRequest(myThreadFunc, argchunk)
pool.wait()

这里的优点是您可以轻松地在 10 个线程上适本地安排 100 个作业,而不是每个线程一个 10 个作业,而无需维护队列等所有工作。缺点是您不能只是迭代线程以获得返回值,您必须迭代作业 — 理想情况下,您不想让作业一直存活到最后,以便您可以迭代它们。

这让我们想到了您的第二个问题,如何从线程(或作业)中获取值。有很多很多方法可以做到这一点。

您所做的工作有效。您甚至不需要任何锁定。

如您所建议的,使用回调也有效。但请记住,回调将在工作线程而不是主线程上运行,因此如果它正在访问某个全局​​对象,您将需要某种同步。

如果您无论如何都要同步,回调可能没有任何好处。例如,如果你想做的只是对一堆值求和,你可以设置 total=[0],让每个线程只做 total[0] +=锁内的 myValue。 (当然,在这种情况下,只在主线程中进行求和并避免锁定可能更有意义,但如果合并结果的工作繁重得多,那么选择可能就不那么简单了。)

您还可以使用某种原子对象,而不是显式锁定。例如,标准 Queue.Queue 和 collections.deque 都是原子的,因此每个线程只需设置 q = Queue.Queue(),然后每个线程通过执行 q 推送其结果。 push(myValue),然后在加入后您只需迭代并总结队列的值。

事实上,如果每个线程只向队列推送一次,您只需对队列本身进行 10 次阻塞获取,之后您知道 group.join()pool.wait() 或任何会快速返回的内容。

或者您甚至可以将回调作为作业推送到队列中。同样,您可以对队列进行 10 次阻塞获取,每次都执行结果。

如果每个线程都可以返回多个对象,则它们可以在完成后将哨兵值或回调推送到队列中,并且您的主线程会不断弹出,直到它读取 10 个哨兵。

关于python - 在 Python 中处理线程连接的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11570824/

相关文章:

python - pyside改变QTreeWidgetItem的颜色

python - 多个文件中的单词匹配

python - 删除包含关键字的行

java - Jmeter行为怪癖

java - 同步块(synchronized block)是否会阻止其他线程访问对象?

mysql - 如何防止此 JOIN 查询进行几乎全表扫描

javascript - 删除 array.slice 之后 array.join 中的持久逗号

python - UnboundLocalError - 赋值前引用的局部变量 - Django

python GIL : is django save() blocking?

Hibernate EntityManager + 查询缓存 - "join fetch"不起作用