3

我想在当前通过多处理实现的程序中使用 spaCy。具体来说,我ProcessingPool用来生成 4 个子进程,然后它们开始执行它们的快乐任务。

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

但我想不出一种方法让他们共享正在加载的对象。这个对象不能被腌制,这意味着(据我所知):

  1. 它不能传递给Pool.map调用
  2. 它不能被Manager实例存储和使用,然后在进程之间共享

我能做些什么?

4

1 回答 1

2

我不知道您是如何使用Pool.map的,但请注意,这Pool.map不适用于大量输入。如您所见,在 Python 3.6 中,它在Lib/multiprocessing/pool.pyiterable中实现,它声明它需要一个作为第一个参数,但实现确实在运行多进程映射之前消耗了整个迭代。因此,我认为Pool.map如果您需要处理大量数据,则不需要使用它。也许Pool.imap并且Pool.imap_unordered可以工作。

关于你的实际问题。我有一个不涉及Pool.map并且工作方式类似于multiprocessforeach的解决方案。

首先需要继承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 的内容必须适合 memory的原因。

如果工人参数(又名。iterable)不能放入内存中,您必须以某种方式同步主进程和工人......

最后确保调用以下命令:

for worker in workers:
    queue.put(None)

for worker in workers:
    worker.join()
于 2017-02-02T13:20:33.477 回答