Несколько экземпляров одной и той же функции асинхронно в Python - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть небольшой скрипт, который выполняет несколько простых задач. Запуск Python 3.7.

Одна из задач должна объединить несколько файлов, что может занять немного времени.

Он проходит по нескольким каталогам, затем каждый каталог передается в функцию. Функция просто просматривает файлы и объединяет их.

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

Я бы хотел использовать лошадиные силы / ядра / потоки, чтобы скрипт объединял PDF-файлы одновременно в несколько каталогов, что должно сократить время.

У меня есть что-то вроде этого:

if multi_directories:
    if os.path.isdir('merged'):
        pass
    else:
        os.makedirs('merged')
    for directory in multi_directories:
        merge_pdfs(directory)

Моя функция слияния PDF выглядит следующим образом:

def merge_pdfs(directory):
    root_dir = os.path.dirname(os.path.abspath(__file__))
    merged_dir_location = os.path.join(root_dir, 'merged')
    dir_title = directory.rsplit('/', 1)[-1]
    file_list = [file for file in os.listdir(directory)]
    merger = PdfFileMerger()
    for pdf in file_list:
        file_to_open = os.path.join(directory, pdf)
        merger.append(open(file_to_open, 'rb'))
        file_to_save = os.path.join(
            merged_dir_location,
            dir_title+"-merged.pdf"
        )
    with open(file_to_save, "wb") as fout:
        merger.write(fout)
    return True

Это прекрасно работает, но merge_pdfs работает медленно в некоторых случаях, когда в каталоге большое количество PDF.

По сути, я хочу иметь возможность циклически проходить по multi_directories, создавать новый поток или процесс для каждого каталога и объединять PDF-файлы одновременно.

Я посмотрел на asyncio, multithreading и множество маленьких фрагментов тут и там, но, похоже, не могу заставить его работать.

1 Ответ

0 голосов
/ 09 ноября 2018

Вы можете сделать что-то вроде:

from multiprocessing import Pool
n_processes = 2
...
if multi_directories:
    if os.path.isdir('merged'):
        pass
    else:
        os.makedirs('merged')
    pool = Pool(n_processes)
    pool.map(merge_pdfs, multi_directories)

Должно помочь, если узким местом является использование процессора. Но это может усугубить ситуацию, если узким местом является жесткий диск, поскольку чтение нескольких файлов параллельно с одного физического жесткого диска обычно происходит медленнее, чем последовательное чтение. Попробуйте это с другими значениями n_processes .

Кстати, для создания списка из итеративного использования list () : file_list = list(os.listdir(directory)). И поскольку listdir () возвращает Список , вы можете просто написать file_list = os.listdir(directory)

...