Самый быстрый способ обработки больших файлов в 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.