【发布时间】:2021-08-29 16:39:45
【问题描述】:
我有一个生成器对象,它会加载大量数据并占用系统的 I/O。数据太大而无法一次全部放入内存,因此使用生成器。 而且我有一个消费者,所有的 CPU 来处理生成器产生的数据。它不会消耗太多其他资源。是否可以使用线程交错这些任务?
例如,我猜可以在 11 秒内运行下面的简化代码。
import time, threading
lock = threading.Lock()
def gen():
for x in range(10):
time.sleep(1)
yield x
def con(x):
lock.acquire()
time.sleep(1)
lock.release()
return x+1
但是,最简单的线程应用程序并没有在那个时候运行。它确实加快了速度,但我认为是因为生成和工作的调度程序之间存在并行性。但不是因为工人之间的并行性。
import joblib
%time joblib.Parallel(n_jobs=2,backend='threading',pre_dispatch=2)((joblib.delayed(con)(x) for x in gen()))
# CPU times: user 0 ns, sys: 0 ns, total: 0 ns
# Wall time: 16 s
【问题讨论】:
-
如果您的问题是
Is it possible ...?那么简单的答案是肯定的。 Python 中的线程不是并行运行的——你需要多个进程。如果您的数据可以分块处理,您可以使用线程进行 I/O 绑定数据获取和分发,每个线程在 获取数据时将数据提供给一个或多个进程。您必须找到一种方法来限制它以节省资源。 Python 有很多内置工具:threading、multiprocessing、concurrent.futures、subprocesses、asyncio。 .... -
如果没有更多细节,很难推荐一个策略。推荐策略可能与 SO 无关——但我会让社区决定。这里有 很多 的 Q&A 涉及您的问题,也许不断完善的搜索将帮助您定义您的策略。 concurrent.futures source 的模块文档字符串很好地展示了他们如何使用线程来提供进程。
-
嗯,可以理解
Is it possible ...?的意思。但是标题为How to ... ?该问题有一个具体的问题示例和一个关于该具体示例的问题。 -
Here is an answer 我写了一些关于未解决内存消耗的负面反馈 - 它使用 concurrent.futures 将数据提供给进程。 Here is another。如果您的生成器可以工作,那么您似乎并不需要线程,只是一种将数据提供给多个进程的方法。同样,您没有说,但我们可以假设数据可以分块处理吗?也许我误读了你的问题 - 这是我的一个坏习惯。
-
@wwii 问题是关于线程的。单个消费者使用所有 cpu,主要使用已发布的 GIL 来处理单个块。第一段是专门为将问题集中在线程而不是进程上而编写的。
标签: python multithreading joblib