python 多处理,为每个进程创建实例并重用它

python multiprocessing, make instance per process and reuse it

我正在使用 pytesseract 通过多处理方法做一些 ocr。

该方法如下所示:

tess_api = PyTessBaseAPI()
Parallel(n_jobs=4)(delayed(execute)(image) for image in images)

具有以下功能:

def execute(image):
    tess_api.SetImage(image)
    text = tess_api.GetUTF8Text()

这会导致并发问题,因为 Worker 1 可能会在 Worker 2 执行 gettext() 之前覆盖图像

现在的想法是让每个工人拥有一个 PyTessBaseAPI 实例。 主要想法是做类似的事情:

tess_apis = [PyTessBaseAPI(), PyTessBaseAPI(), PyTessBaseAPI(), PyTessBaseAPI()]

然后将tess_api[0]交给worker 0但是我不知道如何在worker和instance之间建立连接。 有什么建议,或者更好的方法是什么? 因为我有成千上万的图像,所以我不想在执行函数中创建实例。

在每个工作进程开始读取其作业队列之前,使用 Pool(initializer=...) 初始化 Tesseract 对象一次。

tess_api = None

def initialize_worker():
    global tess_api
    tess_api = PyTessBaseAPI()  # initialize a copy for this instance

def execute(image):
    tess_api.SetImage(image)
    text = tess_api.GetUTF8Text()

def main():
    with multiprocessing.Pool(initializer=initialize_worker) as p:
        for result in p.imap_unordered(images, chunksize=10):
            # ...

这仅在您使用实际流程时才有效;如果您改用线程(这可能有效,考虑到 Tesseract 是 C 并且会发布 GIL),您可以使用 contextvars/threading.local.

Pool(initializer=...) 可以像上面提到的那样工作。但是,如果您想做更复杂的事情,我建议您使用 Ray.

则表示如下。

import ray

ray.init()

@ray.remote
class Worker(object):
    def __init__(self):
        self.tess_api = PyTessBaseAPI()

    def execute(self, image):
        self.tess_api.SetImage(image)
        return self.tess_api.GetUTF8Text()

# Create several Worker actors.
workers = [Worker.remote() for _ in range(4)]

# Execute tasks on them in parallel.
result_ids = [worker.execute.remote(image) for worker in workers]

# Get the results
results = ray.get(result_ids)

您可以阅读有关 Ray in the documentation 的更多信息。请注意,我帮助开发 Ray。