Самый быстрый способ обработки больших файлов в Python

У нас есть около 500 ГБ изображений в разных каталогах, которые нам нужно обрабатывать. Каждое изображение имеет размер около 4 МБ, и у нас есть python script для обработки каждого изображения по одному (он считывает метаданные и сохраняет их в базе данных). Каждый каталог может занимать 1-4 часа для обработки в зависимости от размера.

У нас в распоряжении 2,2 ГГц четырехъядерный процессор и 16 ГБ оперативной памяти на ОС GNU/Linux. Текущий script использует только один процессор. Какой лучший способ использовать другие ядра и оперативную память для ускорения обработки изображений? Будет ли запуск нескольких процессов Python для запуска script использовать другие ядра?

Другой вариант - использовать что-то вроде Gearman или Beanstalk для фермы вне зависимости от работы с другими машинами. Я взглянул на многопроцессорную библиотеку, но не уверен, как я могу ее использовать.

Ответ 1

Будет ли запущено несколько процессов Python для запуска script использовать другие ядра?

Да, это будет, если задача связана с ЦП. Вероятно, это самый простой вариант. Однако не создавайте ни одного процесса для каждого файла или каталога; рассмотрите возможность использования такого инструмента, как parallel(1), и пусть это порождает что-то вроде двух процессов на ядро.

Другой вариант - использовать что-то вроде Gearman или Beanstalk для работы с другими машинами.

Это может сработать. Кроме того, взгляните на привязку Python для ZeroMQ, он упрощает распределенную обработку.

Я просмотрел многопроцессорную библиотеку, но не знаю, как ее использовать.

Определите функцию, скажем process, которая читает изображения в одном каталоге, подключается к базе данных и сохраняет метаданные. Пусть он возвращает логическое значение, указывающее на успех или неудачу. Пусть directories - список каталогов для обработки. Тогда

import multiprocessing
pool = multiprocessing.Pool(multiprocessing.cpu_count())
success = all(pool.imap_unordered(process, directories))

будет обрабатывать все каталоги параллельно. Вы также можете сделать parallelism на уровне файла, если хотите; это требует немного более возиться.

Обратите внимание, что это остановится при первом сбое; что делает его отказоустойчивым, требует немного больше работы.

Ответ 2

Запуск независимых процессов Python идеален. Между процессами не будет ограничений на блокировку, и ОС будет планировать их запуск одновременно.

Вы можете поэкспериментировать, чтобы узнать, что представляет собой идеальное количество экземпляров - оно может быть больше или меньше количества ядер. Будут споры о дисковой и кэш-памяти, но, с другой стороны, вы можете запустить один процесс, в то время как другой ожидает ввода-вывода.

Ответ 3

Вы можете использовать пул многопроцессорности для создания процессов для повышения производительности. Скажем, у вас есть функция handle_file, которая предназначена для обработки изображения. Если вы используете итерацию, она может использовать не более 100% от вашего ядра. Чтобы использовать несколько ядер, многопроцессорность пула создает подпроцессы для вас и распределяет вашу задачу с ними. Вот пример:

import os
import multiprocessing

def handle_file(path):
    print 'Do something to handle file ...', path

def run_multiprocess():
    tasks = []

    for filename in os.listdir('.'):
        tasks.append(filename)
        print 'Create task', filename

    pool = multiprocessing.Pool(8)
    result = all(list(pool.imap_unordered(handle_file, tasks)))
    print 'Finished, result=', result

def run_one_process():
    for filename in os.listdir('.'):
        handle_file(filename)

if __name__ == '__main__':
    run_one_process
    run_multiprocess()

run_one_process - это одноядерный способ обработки данных, простой, но медленный. С другой стороны, run_multiprocess создает 8 рабочих процессов и распределяет с ними задачи. Это будет примерно в 8 раз быстрее, если у вас 8 ядер. Я предлагаю вам установить рабочий номер в два раза по сравнению с вашими ядрами или точно по количеству ваших ядер. Вы можете попробовать и посмотреть, какая конфигурация выполняется быстрее.

Для расширенных распределенных вычислений вы можете использовать ZeroMQ в качестве упомянутых выше larsmans. Трудно понять сначала. Но как только вы это понимаете, вы можете создать очень эффективную распределенную систему для обработки ваших данных. В вашем случае, я думаю, что один REQ с несколькими REP будет достаточно хорошим.

enter image description here

Надеюсь, что это будет полезно.

Ответ 4

Смотрите ответ на этот question.

Если приложение может обрабатывать диапазоны входных данных, вы можете запустить 4 экземпляры приложения с различными диапазонами входных данных для обработки и объединить результаты после их завершения.

Несмотря на то, что этот вопрос относится к Windows, он применяется к однопоточным программам во всех операционных системах.

ПРЕДУПРЕЖДЕНИЕ:. Остерегайтесь того, что этот процесс будет связан с I/O, и слишком много одновременного доступа к вашему жесткому диску фактически вызовет процессы как группу для выполнения медленнее, чем последовательная обработка из-за конкуренции за ресурс ввода-вывода.

Ответ 5

Если вы читаете большое количество файлов и сохраняете метаданные в базе данных, вам не требуется больше ядер.

Ваш процесс, скорее всего, связан с IO, а не с привязкой к ЦП. Использование скрученных с надлежащими отсрочками и обратными вызовами, вероятно, будет превосходить любое решение, которое предназначено для привлечения 4 ядер.

Ответ 6

Я думаю, что в этом случае было бы разумно использовать Celery.