многопроцессорная обработка на Python, создание экземпляра для каждого процесса и повторное его использование - PullRequest
0 голосов
/ 24 мая 2019

Я использую 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] работнику 0, но я не знаю, как я могу установить связь между работником и экземпляром. Любые предложения, или что было бы лучше? Поскольку у меня есть тысячи изображений, я не хочу создавать экземпляры внутри функции execute.

Ответы [ 2 ]

1 голос
/ 25 мая 2019

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 вы можете прочитать в документации . Обратите внимание, что я помогаю развивать Рэя.

1 голос
/ 24 мая 2019

Используйте 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...