параллельный разбор файлов, несколько процессорных ядер - PullRequest
12 голосов
/ 29 октября 2010

Я задал связанный, но очень общий вопрос ранее (см. Особенно этот ответ ).

Этот вопрос очень специфический. Это весь код, который мне важен:

result = {}
for line in open('input.txt'):
  key, value = parse(line)
  result[key] = value

Функция parse полностью автономна (т.е. не использует общие ресурсы).

У меня процессор Intel i7-920 (4 ядра, 8 потоков; я думаю, что потоки более актуальны, но я не уверен).

Что я могу сделать, чтобы моя программа использовала все параллельные возможности этого процессора?

Я предполагаю, что могу открыть этот файл для чтения в 8 различных потоках без особых потерь производительности, поскольку время доступа к диску мало по сравнению с общим временем.

Ответы [ 6 ]

18 голосов
/ 29 октября 2010

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)
8 голосов
/ 29 октября 2010
  1. разделить файл на 8 меньших файлов
  2. запустить отдельный скрипт для обработки каждого файла
  3. присоединиться к результатам

Почему это лучший способ ...

  • Это просто и легко - вам не нужно программировать каким-либо образом, отличным от линейной обработки.
  • Вы получаете наилучшую производительность, запуская небольшое количество длительных процессов.
  • ОС будет иметь дело с переключением контекста и мультиплексированием ввода-вывода, поэтому вам не придется беспокоиться об этом (ОС хорошо справляется).
  • Вы можете масштабировать до нескольких машин, не меняя код вообще
  • ...
3 голосов
/ 05 февраля 2019

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

Чтобы запустить приведенный ниже код, сначала создайте input.txt следующим образом.

printf "1\n2\n3\n4\n5\n6\n" > input.txt

Затем вы можете параллельно обрабатывать файл, добавив декоратор @ray.remote к функции parse и выполнив несколько копий параллельно, как показано ниже

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 .

0 голосов
/ 18 августа 2016
  • создание распределенной архитектуры с rabbitMQ, один производитель задач читает файл построчно и отправляет строки рабочим через rabbitMQ
  • , используя консольную утилиту, такую ​​как unix /rallel, xargs
    $ python makelist.py | parallel -j+2 'wget "{}" -O - | python parse.py'
    
    или этастиль
$ ls *.wav | xargs -n1 --max-procs=4 -I {} lame {} -o {}.mp3

В любом случае, вам необходимо реализовать карту / уменьшить парадигму

0 голосов
/ 29 октября 2010

Как сказал TokenMacGuy, вы можете использовать модуль multiprocessing.Если вам действительно нужно проанализировать огромное количество данных, вам следует проверить диско-проект .

Дискотека - это распределеннаявычислительная структура на основе парадигмы MapReduce.Дискотека с открытым исходным кодом;разработанный исследовательским центром Nokia для решения реальных проблем при работе с большими объемами данных.

Это действительно масштабируется для заданий, в которых задание parse () является «чистым» (т. е. не использует общий доступресурсы) и интенсивно использует процессор.Я протестировал работу на одном ядре, а затем сравнил ее с работой на 3 хостах по 8 ядер на каждом.На самом деле он работал в 24 раза быстрее при запуске на кластере Disco (ПРИМЕЧАНИЕ: проверено на необоснованно интенсивную загрузку процессора).

0 голосов
/ 29 октября 2010

Вы можете использовать модуль multiprocessing, но если parse () работает быстро, вы не добьетесь значительного улучшения производительности.

...