多处理时避免在每个子进程中加载​​spaCy数据

时间:2017-02-01 20:17:10

标签: python pickle python-multiprocessing spacy

我想在目前使用多处理实现的程序中使用spaCy。具体来说,我正在使用ProcessingPool来生成4个子进程,然后这些子进程就会完成他们的快乐任务。

要使用spaCy(专门用于POS标记),我需要调用spacy.load('en'),这是一个昂贵的调用(需要大约10秒)。如果我要在每个子进程中加载​​此对象,则需要约40秒,因为它们都是从同一位置读取的。这太烦人了。

但我无法弄清楚让他们分享正在加载的对象的方法。这个对象不能被腌制,这意味着(据我所知):

  1. 无法将其传递到Pool.map来电
  2. Manager实例无法存储和使用它,然后在进程间共享
  3. 我该怎么办?

1 个答案:

答案 0 :(得分:2)

我不知道你如何准确使用Pool.map,但请注意Pool.map不能处理大量输入。在Python 3.6中,它在Lib/multiprocessing/pool.py中实现,如您所见,它声明它需要iterable作为第一个参数,但实现在运行多进程映射之前执行consume the whole iterable。因此,如果您需要处理大量数据,我认为您不需要Pool.map。也许Pool.imapPool.imap_unordered可以有效。

关于您的实际问题。我有一个不涉及Pool.map的解决方案,并且类似多进程foreach

首先,您需要继承Pool并创建一个工作进程:

from multiprocessing import cpu_count
from multiprocessing import Queue
from multiprocessing import Process


class Worker(Process):

    english = spacy.load('en')

    def __init__(self, queue):
        super(Worker, self).__init__()
        self.queue = queue

    def run(self):
        for args in iter(self.queue.get, None):
            # process args here, you can use self.

您准备了这样的流程池:

queue = Queue()
workers = list()
for _ in range(cpu_count()):  # minus one if the main processus is CPU intensive
    worker = Worker(queue)
    workers.append(worker)
    worker.start()

然后您可以通过queue

来提供游泳池
for args in iterable:
    queue.put(args)

iterable是您传递给工作人员的参数列表。上面的代码会尽可能快地推送iterable的内容。基本上,如果工人足够慢,几乎所有的iterable都会在工人完成工作之前被推到队列中。这就是为什么迭代的内容必须适合内存

如果工人的论点(又名。iterable)不能适应记忆,你必须以某种方式同步主要的工作流程和工人......

最后请务必致电以下人员:

for worker in workers:
    queue.put(None)

for worker in workers:
    worker.join()