这是我previous question的后续跟进。正如Tim Peters所建议的那样,使用Manager
可能不一定是最好的方法。不幸的是,我有太多的脚手架代码来发布SSCCE。相反,我会尝试提供我的问题的详细解释。请随意浏览Github上的整个代码库,但现在有点混乱。
我正在进行自然语言处理方面的研究,我想做(如类似的)基于字典的平滑文档分类。培养分类器以将单词和短语与正确答案相关联的想法。例如,包含单词socialist
的文档可能与政治有关,而包含短语lava temperature
的文档可能与地质有关。通过查看少数预先标记的示例来训练系统。因为语言是如此多样化,分类器永远不会“知道”它在生产中可能遇到的所有可能的短语。
这就是字典的用武之地。假设我们有a cheap and easy way获取几乎所有短语的同义词(我会引用自己,因为它的味道很差)。当穷人的分类器面对一个它不知道的短语时,我们可以在所说的字典中查找并告诉分类器“看,你不知道communism
,但它有点像{{1} ,你知道的!“如果字典合理,分类器通常会表现得更好。
socialist
上面的循环是并行化的理想选择。我一直在使用Python 2.7 data = Load training and testing documents (300MB on disk)
dictionary = Load dictionary (200MB - 2GB on disk) and place into a `dict` for fast look-ups
Repeat 25 times:
do_work(data, dictionary)
def do_work(data, dictionary)
X = Select a random sample of data
Train a classifier on X
Y = Select a random sample of data
Using dictionary, classify all documents in Y
Write results to disk
(通过multiprocessing.Pool
,因为它很容易,并且如果事情向南,则提供非常有用的回溯)。所有工作进程都需要对字典和文档集合的只读访问权限。工作人员不需要彼此沟通或与父流程进行通信 - 他们所做的就是产生,做一些魔术,写一个文件并死掉。
字典需要支持快速随机访问。我不知道样本joblib.Parallel
将包含哪些文档,因此我无法轻松修剪字典并仅传递每个工作者所需的部分字典。字典将经常被查询 - 每次运行的典型命中数是数百万。
目前我的代码是内存绑定的(我相信)正在为每个工作进程创建文档集合和字典的副本。解析时Y
和data
通常会占用几GB的RAM。我尝试使用dictionary
来避免复制大型对象,但这会减慢工作人员的速度。
还有哪些其他选择可以加快速度?我想过的事情包括:
multiprocessing.managers.BaseManager
数据库和数据库连接不能跨进程共享,因此每个工作程序都需要自己的连接到磁盘数据库。这意味着当每个工作者的缓存增长时,首先会有大量的I / O和高内存使用量。 This SO question还表示许多看似需要只读sqlite
的实际问题可能会触发dict
的写时复制,因此可能会不可能完全避免复制大型物体。
答案 0 :(得分:2)
您描述的方案,在使用多线程时,由于GIL,您可能会遇到大的性能问题。可能要避免您选择使用多处理。另一方面,这使用了进程,因此可能会为每个子进程复制数据结构。
我不想这么说,但是使用非Python解决方案(例如在C ++中)可能会加快速度,因为你没有GIL问题。然后你可以使用多线程,不必复制东西等。从几个线程读取一个大字典并不是一个真正的问题,所以你不必同步任何东西(GIL总是会为你做什么没有真正的需要)。