Многопроцессорный вопрос Python?

У меня есть папка с 500 входными файлами (общий размер всех файлов ~ 500[МБ]).

Я хотел бы написать скрипт python, который делает следующее:

(1) загрузить все входные файлы в память

(2) инициализирует пустой список python, который будет использоваться позже... см. маркер (4)

(3) запускать 15 разных (независимых) процессов: каждый из них использует одни и те же входные данные [из (1)], но использует разные алгоритмы для их обработки, что приводит к разным результатам.

(4) Я хочу, чтобы все независимые процессы [из шага (3)] сохраняли свои выходные данные в одном и том же списке python [тот же список, который был инициализирован на шаге (2)]

Как только все 15 процессов завершат свое выполнение, у меня будет one python list, включающий результаты всех 15 независимых процессов.

Мой вопрос в том, возможно ли сделать это эффективно в python? если да, можете ли вы предоставить схему/пример кода, иллюстрирующий, как это сделать?

Примечание №1: я буду запускать это на сильном многоядерном сервере; поэтому цель здесь состоит в том, чтобы использовать всю вычислительную мощность, разделяя часть памяти {input data, output list} между всеми независимыми процессами.

Примечание 2. Я работаю в среде Linux.


person user3262424    schedule 30.06.2011    source источник
comment
Это не сработает. Со всеми разногласиями по поводу одного списка вы, вероятно, не увидите большой выгоды от параллелизма.   -  person Rafe Kettler    schedule 01.07.2011
comment
@Rafe Kettler: Что бы вы предложили? моя цель здесь состоит в том, чтобы иметь возможность «агрегировать» результаты в конце обработки; какие есть альтернативы? (для ясности, output list будет иметь размер ~ 100 [МБ]).   -  person user3262424    schedule 01.07.2011
comment
я вижу, как он работает с zeromq. несколько издателей, один подписчик. и подписчик управляет списком. Итак, у меня есть вопрос № 1: есть ли библиотеки третьей части на столе? и № 2: как представляются выходные данные?   -  person Tom Willis    schedule 01.07.2011
comment
Я работал над независимыми списками, а затем сразу их объединял. Очевидно, что этот подход будет использовать больше памяти, поэтому вам, возможно, придется перейти на диск.   -  person Rafe Kettler    schedule 01.07.2011
comment
@ Том Уиллис: спасибо; Ответы на ваши вопросы: #1 --› нет, нет сторонних библиотек; В основном я использую только стандартные библиотеки python; #2 --› выходной список, вероятно, будет многомерным массивом, в идеале с использованием numpy; в любом случае он будет содержать только числа (или массивы с числами, учитывая многомерность). Не могли бы вы уточнить, как здесь следует использовать zeromq? будет ли это решение использовать всю вычислительную мощность сервера?   -  person user3262424    schedule 01.07.2011
comment
@Rafe Kettler: я не хочу переходить на диск; это замедлит меня; помимо этого, как мне использовать всю вычислительную мощность сервера и иметь 15 процессов, которые используют одни и те же входные данные?   -  person user3262424    schedule 01.07.2011
comment
@user — это классическая проблема параллелизма, которую нелегко решить.   -  person Rafe Kettler    schedule 01.07.2011
comment
@Rafe Kettler: Можно ли решить это в python? Если да, можете ли вы предложить, какие библиотеки использовать/как к этому подойти?   -  person user3262424    schedule 01.07.2011
comment
@user3262424 user3262424, как вы видите, я собрал демонстрационное приложение, демонстрирующее, как сделать что-то подобное с 0mq. Я думаю, что суть проблемы заключается в связи между процессами. zeromq делает это намного проще, чем механизмы, предоставляемые многопроцессорной IMO. ценность, которую он добавляет для вашей конкретной проблемы, заключается в том, что один подписчик общается с несколькими издателями. в любом случае надеюсь, что это поможет   -  person Tom Willis    schedule 01.07.2011
comment
Чтобы использовать всю обработку сервера с Python, у вас должно быть несколько процессов, по крайней мере, по одному на ядро. Кроме того, вам нужно, чтобы они были слабо связаны, т. е. использовали неблокирующие коммуникации, такие как ZeroMQ. Люди часто пытаются использовать каналы, но затем блокируют свои рабочие процессы. Проще использовать ZeroMQ   -  person Michael Dillon    schedule 01.07.2011
comment
@Майкл Диллон: спасибо. Итак, zeroMQ если кто-то хочет запустить один master процесс и много (скажем, N) связанных с ним дочерних процессов? (скажем, использовать одну и ту же память? один и тот же вывод?)   -  person user3262424    schedule 01.07.2011
comment
ZeroMQ позволяет запускать любое количество слабо связанных независимых процессов на одном сервере или на сотнях серверов. ZeroMQ — это расширение двухточечного сокета, которое имеет только два конца. Сокет ZeroMQ может иметь один SUB-конец на главном процессе, а многие PUB-концы на нескольких независимых рабочих процессах.   -  person Michael Dillon    schedule 01.07.2011
comment
@Майкл Диллон: я ничего не понял о SUB и PUB -- не могли бы вы объяснить подробнее? Кроме того, что произойдет со всеми процессами, если главный узел выйдет из строя?   -  person user3262424    schedule 01.07.2011
comment
Прочтите руководство по ZeroMQ, чтобы понять, что означают PUB и SUB. zguide.zeromq.org/page:all Что касается ваших дочерних процессов, это отдельный вопрос и это зависит от того, как они запускаются и демонизируют ли они себя. В UNIX, когда умирает лидер группы процессов, умирают и все его потомки.   -  person Michael Dillon    schedule 01.07.2011
comment
@Майкл Диллон: спасибо, я прочитаю документы.   -  person user3262424    schedule 01.07.2011


Ответы (1)


хорошо, я только что сделал это, используя zeromq, чтобы продемонстрировать одного подписчика нескольким издателям. Вероятно, вы могли бы сделать то же самое с очередями, но вам нужно было бы немного больше управлять ими. сокеты zeromq просто работают, что делает их удобными для таких вещей, как эта IMO.

"""
demo of multiple processes doing processing and publishing the results
to a common subscriber
"""
from multiprocessing import Process


class Worker(Process):
    def __init__(self, filename, bind):
        self._filename = filename
        self._bind = bind
        super(Worker, self).__init__()

    def run(self):
        import zmq
        import time
        ctx = zmq.Context()
        result_publisher = ctx.socket(zmq.PUB)
        result_publisher.bind(self._bind)
        time.sleep(1)
        with open(self._filename) as my_input:
            for l in my_input.readlines():
                result_publisher.send(l)

if __name__ == '__main__':
    import sys
    import os
    import zmq

    #assume every argument but the first is a file to be processed
    files = sys.argv[1:]

    # create a worker for each file to be processed if it exists pass
    # in a bind argument instructing the socket to communicate via ipc
    workers = [Worker(f, "ipc://%s_%s" % (f, i)) for i, f \
               in enumerate((x for x in files if os.path.exists(x)))]

    # create subscriber socket
    ctx = zmq.Context()

    result_subscriber = ctx.socket(zmq.SUB)
    result_subscriber.setsockopt(zmq.SUBSCRIBE, "")

    # wire up subscriber to whatever the worker is bound to 
    for w in workers:
        print w._bind
        result_subscriber.connect(w._bind)

    # start workers
    for w in workers:
        print "starting workers..."
        w.start()

    result = []

    # read from the subscriber and add it to the result list as long
    # as at least one worker is alive
    while [w for w in workers if w.is_alive()]:
        result.append(result_subscriber.recv())
    else:
        # output the result
        print result

о, и чтобы получить zmq просто

$ pip install pyzmq-static
person Tom Willis    schedule 01.07.2011
comment
@ Том Уиллис: спасибо! Будет ли приведенный выше код использовать всю вычислительную мощность сервера? Кроме того, можете ли вы подтвердить, что list, в котором хранится этот вывод, будет обрабатываться в памяти без необходимости доступа к диску? Кроме того, когда я запускаю команду Linux top -- я увижу 1 процесс python или 15 разных процессов? - person user3262424; 01.07.2011
comment
вы увидите процесс вверху для каждого запущенного вами рабочего процесса + основной процесс, в коде выше этот список находится в памяти, хорошо это или плохо, зависит от ваших целей. Приведенный выше сценарий обращается к диску только для чтения файлов, переданных в качестве аргументов. Я просто хотел продемонстрировать, как можно организовать межпроцессное взаимодействие и насколько просто это сделать с помощью 0mq. - person Tom Willis; 01.07.2011
comment
последняя вещь, которая может быть неочевидной. сообщения между процессами должны быть строками. если вам нужна дополнительная структура ваших данных, используйте что-то вроде json - person Tom Willis; 01.07.2011
comment
+1 Первоначальный запрос на самом деле невозможен, как написано, но правильный способ сделать это - использовать несколько независимых процессов Python, а zmq - отличный способ связать их вместе. А если вашей многоядерной машины недостаточно, просто измените сокет на использование tcp://my_ip_address:10001, и вы сможете без проблем запускать их на нескольких машинах. Ошибка в вопросе заключалась в том, чтобы сначала загрузить все данные в память, а потом запускать процессы. Оставьте его в файлах и отправьте ответы главному процессу через очередь PUB-SUB. - person Michael Dillon; 01.07.2011
comment
@ Том Уиллис: спасибо. Итак, если я правильно вас понял, процессы child отправят strings главному процессу? и эти strings нужно будет разобрать и потом сохранить в выходной список? Я правильно понял? если да, то есть ли ограничение на размер строки? - person user3262424; 01.07.2011
comment
@Michael Dillon: Если я сначала не загружу все данные в память, каждый процесс должен будет загрузить их в память, что приведет к потере в 15 раз больше памяти (потому что данные одинаковы). имеет ли это смысл? Кроме того, не могли бы вы рассказать о своем альтернативном решении (и, возможно, предоставить образец)? благодарю вас - person user3262424; 01.07.2011
comment
@user да, json — отличный транспортный формат для этого. что касается ограничений на сообщение, мне придется проконсультироваться с документами zeromq для этого. Я смог ответить на этот вопрос только потому, что прошлой ночью во время взлома мне пришлось придумать что-то очень похожее. :) - person Tom Willis; 01.07.2011
comment
Что касается потребления памяти, почему бы не провести пробную версию с использованием mmap, а затем еще раз, когда вы загружаете все файлы перед разветвлением. Я думаю, что разница будет небольшой, если вы работаете в Linux. Если на то пошло, почему бы не задать еще один вопрос конкретно об этих двух альтернативах? - person Michael Dillon; 01.07.2011
comment
@Майкл Диллон: я думаю, оба подхода могут работать. Нужно посмотреть, какой из них лучше подходит. Просто чтобы понять, является ли zmq РЕШЕНИЕм любых проблем с масштабируемостью? то есть, если вы хотите, чтобы программа работала, скажем, на 1000 процессах (на N компьютерах) -- zmq может быть мостом, который соединяет их всех с одним главным узлом? - person user3262424; 01.07.2011
comment
@user, пожалуйста. zeromq действительно чертовски крут. это делает межпроцессное взаимодействие очень простым, если ваша проблема может быть выражена как сочетание топологии сети, которую он поддерживает. проведите выходные, играя с ним, следуйте документации, и вы, как и я, обнаружите, что он открывает целый мир возможностей для решения проблем, связанных с несколькими процессами. - person Tom Willis; 01.07.2011