Параллельный анализ файлов, несколько ядер процессора
Я задал ранее связанный, но очень общий вопрос (см. особенно этот ответ).
Этот вопрос очень конкретный. Это все код, который мне очень нравится:
result = {}
for line in open('input.txt'):
key, value = parse(line)
result[key] = value
Функция parse
полностью автономна (т.е. не использует общие ресурсы).
У меня есть процессор Intel i7-920 (4 ядра, 8 потоков, я думаю, что потоки более актуальны, но я не уверен).
Что я могу сделать, чтобы моя программа использовала все параллельные возможности этого процессора?
Я предполагаю, что я могу открыть этот файл для чтения в 8 разных потоках без большого снижения производительности, поскольку время доступа к диску невелико относительно общего времени.
Ответы
Ответ 1
cPython не предоставляет модель потоков, которую вы ищете легко. Вы можете получить что-то подобное с помощью модуля multiprocessing
и пула процессов
такое решение может выглядеть примерно так:
def worker(lines):
"""Make a dict out of the parsed, supplied lines"""
result = {}
for line in lines.split('\n'):
k, v = parse(line)
result[k] = v
return result
if __name__ == '__main__':
# configurable options. different values may work better.
numthreads = 8
numlines = 100
lines = open('input.txt').readlines()
# create the process pool
pool = multiprocessing.Pool(processes=numthreads)
# map the list of lines into a list of result dicts
result_list = pool.map(worker,
(lines[line:line+numlines] for line in xrange(0,len(lines),numlines) ) )
# reduce the result dicts into a single dict
result = {}
map(result.update, result_list)
Ответ 2
- разделить файл на 8 небольших файлов
- запустить отдельный script для обработки каждого файла
- присоединиться к результатам
Почему это лучший способ...
- Это просто и просто - вам не нужно программировать ничем не отличающимся от линейной обработки.
- У вас есть лучшая производительность, запустив небольшое количество длительных процессов.
- ОС будет иметь дело с переключением контекста и мультиплексированием ввода-вывода, поэтому вам не придется беспокоиться об этом (ОС хорошо справляется).
- Вы можете масштабировать до нескольких машин, не изменяя код вообще
- ...
Ответ 3
Вы можете использовать модуль multiprocessing
, но если функция parse() выполняется быстро, вы не получите большого улучшения производительности, выполнив это.
Ответ 4
Как сказал TokenMacGuy, вы можете использовать модуль multiprocessing
. Если вам действительно нужно разобрать массивный объем данных, вы должны проверить проект .
Дискотека - это распределенные вычисления основываясь на MapReduce парадигма. Дискотека с открытым исходным кодом; разработанный Nokia Research Center для решать реальные проблемы при обработке огромное количество данных.
Он действительно масштабируется для заданий, где ваша задача parse() является "чистой" (т.е. не использует общие ресурсы) и имеет интенсивность процессора. Я протестировал работу на одном ядре, а затем сравнил ее с тремя хостами с 8 ядрами. Фактически он работал в 24 раза быстрее, когда запускался в кластере Disco (ПРИМЕЧАНИЕ: проверено на неоправданно интенсивную работу ЦП).
Ответ 5
$ ls *.wav | xargs -n1 --max-procs=4 -I {} lame {} -o {}.mp3
В любом случае вам нужно реализовать парадигму map/reduce
Ответ 6
Это можно сделать с помощью Ray, библиотеки для написания параллельного и распределенного Python.
Чтобы запустить приведенный ниже код, сначала создайте input.txt
следующим образом.
printf "1\n2\n3\n4\n5\n6\n" > input.txt
Затем вы можете обработать файл параллельно, добавив декоратор @ray.remote
в функцию parse
и выполнив несколько копий параллельно, как @ray.remote
ниже.
import ray
import time
ray.init()
@ray.remote
def parse(line):
time.sleep(1)
return 'key' + str(line), 'value'
# Submit all of the "parse" tasks in parallel and wait for the results.
keys_and_values = ray.get([parse.remote(line) for line in open('input.txt')])
# Create a dictionary out of the results.
result = dict(keys_and_values)
Обратите внимание, что оптимальный способ сделать это будет зависеть от того, сколько времени потребуется для запуска функции parse
. Если это занимает одну секунду (как указано выше), то имеет смысл разбирать одну строку на задачу Ray. Если это занимает 1 миллисекунду, то, вероятно, имеет смысл проанализировать несколько строк (например, 100) для задачи Ray.
Ваш сценарий достаточно прост, чтобы можно было использовать многопроцессорный модуль, однако, как только вы захотите сделать что-нибудь более сложное или захотите использовать несколько машин вместо одной машины, с Ray это будет намного проще.
Смотрите документацию Ray.