Как выполнить многопроцессорную обработку модуля продукта itertools?

Итак, я попытался рассчитать миллионы и миллионы различных комбинаций приведенной ниже строки, но я вычислял только примерно 1750 комбинаций в секунду, что даже близко не соответствует скорости, которая мне нужна. Итак, как мне изменить это, чтобы несколько процессов одной и той же вещи вычисляли разные части, не вычисляя части, которые уже были рассчитаны, и при этом сохраняя высокие скорости? Приведенный ниже код частично является тем, что я использовал. Буду признателен за любые примеры!

from itertools import product
for chars in product("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12234567890!@#$%^&*?,()-=+[]/;", repeat = 4):
   print chars

person Noah R    schedule 21.04.2012    source источник


Ответы (2)


Один из способов разбить продукт на части — разбить первый компонент продукта, чтобы в каждом независимом задании были все элементы, начинающиеся с определенного набора первых букв. Например:

import string
import multiprocessing as mp
import itertools

alphabet = string.ascii_letters+string.digits+"!@#$%^&*?,()-=+[]/;"
num_parts = 4
part_size = len(alphabet) // num_parts

def do_job(first_bits):
    for x in itertools.product(first_bits, alphabet, alphabet, alphabet):
        print(x)

if __name__ == "__main__":
    pool = mp.Pool()
    results = []
    for i in xrange(num_parts):
        if i == num_parts - 1:
            first_bit = alphabet[part_size * i :]
        else:
            first_bit = alphabet[part_size * i : part_size * (i+1)]
        results.append(pool.apply_async(do_job(first_bit)))

    pool.close()
    pool.join()

(где, очевидно, вы бы использовали results только в том случае, если do_job действительно что-то вернуло).

person Danica    schedule 21.04.2012
comment
Хорошо, я сделал это, и он завершил себя примерно за 10 секунд. Плохо то, что все ресурсы моего компьютера были заняты, и у него чуть не случился сердечный приступ. Как я могу ограничить это количество потоков, потому что у меня был диспетчер задач, и у меня одновременно работало около 80 процессов Python. - person Noah R; 21.04.2012
comment
:) Именно для этого я пропустил ... в multiprocessing.Pool. Попробуйте, например. Pool(processes=4). Дополнительные сведения см. в документах по многопроцессорной обработке. - person Danica; 21.04.2012
comment
Ну, я переключил его на 4 процесса, и стало еще хуже, и у меня было несколько сотен одновременно, а затем мой компьютер завис. - person Noah R; 21.04.2012
comment
Если вы говорите 4 процесса, то multiprocessing должно запускать только 4 процесса - вы делаете что-то еще в своем коде, который запускает процессы Python? - person Danica; 21.04.2012
comment
Нет, я буквально скопировал приведенный выше код, создал с ним новый проект Python и запустил код, переключающий пул на 4 процесса. - person Noah R; 21.04.2012
comment
Я только что обновил вопрос, указав точный код, который я запустил (поместив его в test_multi.py и запустив python test_multi.py, то есть Python 2.7.2), который запустил четыре процесса и довольно успешно распечатал кортежи. Было запущено пять процессов (один главный плюс четыре в пуле), и все было в порядке, за исключением того, что мой терминал использовал 100% ЦП, пытаясь не отставать от всего вывода. Разве это не то, что вы видите? Как ты это делаешь? - person Danica; 21.04.2012
comment
Хорошо, я запустил скрипт с двумя процессами, получил 80% ЦП и, вероятно, более 400 процессов, использующих в среднем 1200 КБ памяти. Это начинается примерно с 5, но затем они умножаются на сотни. Я попытался сделать снимок экрана, но мой компьютер снова дал сбой. Я проверил обновленный код, и он совпадает с моим, за исключением того, что в третий раз я добавил только 2 процесса. Действительно не помогло. - person Noah R; 21.04.2012
comment
Что более интересно, я использовал один из примеров документации, и он работал, создавая указанные процессы. Так что я думаю, что это что-то в вашем коде. - person Noah R; 22.04.2012
comment
@NoahR Держу пари, ты на Windows, верно? multiprocessing фактически импортирует модуль в Windows, в отличие от ОС Unix, таких как моя, где этого не происходит, поэтому каждый элемент пула порождал свой собственный пул. Попробуйте новую версию с проверкой __main__. - person Danica; 22.04.2012
comment
@Dougal Спасибо за этот замечательный пример кода, который вы написали. Я пытаюсь сделать что-то подобное... Итак, скажем, вместо того, чтобы печатать x, вы ищете совпадение. Как выйти из всех процессов, когда совпадение найдено? - person user2109254; 07.06.2016
comment
@user2109254 user2109254 Вы, вероятно, захотите перебрать imap_unordered< /a> с возвратом do_work, когда он увидит результат, а затем, когда вы получите совпадение, вызовите pool.terminate() (а затем join()). - person Danica; 07.06.2016

Вы уверены, что получаете только 1750 комбинаций в секунду? Я получаю около 10 миллионов.

def test(n):
    start = time.time()
    count = 0
    for chars in product("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12234567890!@#$%^&*?,()-=+[]/;", repeat = 4):

        count += 1
        if count == n: break
    return time.time() - start    

>>> test(10000)
0.03300023078918457
>>> test(1000000)
0.15799999237060547
>>> test(10000000)
1.0469999313354492

Не думаю, что мой компьютер намного быстрее вашего.

примечание: я разместил это как ответ, потому что хотел показать код. Это действительно больше комментарий. Так что, пожалуйста, без плюсов и минусов.

person Steven Rumbalski    schedule 21.04.2012
comment
Отличие, вероятно, в том, что OP printing, пока вы просто прокручиваете; Ввод/вывод медленный. - person Danica; 21.04.2012
comment
Что ж, мой основной скрипт на самом деле сохраняет в базу данных, поскольку он вычисляет различные комбинации, что также значительно замедляет его. - person Noah R; 21.04.2012
comment
@Dougal: Согласен, ввод-вывод медленный. Его вопрос определяет itertools.product как узкое место. Если он измеряет время с помощью ввода-вывода, это должно его подсказать. - person Steven Rumbalski; 21.04.2012
comment
@Noah R: Основываясь на вашем комментарии, я бы сказал, что вы неправильно диагностировали настоящее узкое место. Неважно, на сколько процессов вы разбиваете это, ввод-вывод будет вашим узким местом. Если вы распределяете ввод-вывод на несколько процессов, каждый из которых подключается к вашей базе данных, вероятно, будет еще медленнее. - person Steven Rumbalski; 21.04.2012
comment
Ну, так как он сказал, что это быстро завершилось с использованием огромного multiprocessing.Pool, очевидно, что параллелизм помогает ему... но да, itertools.product также явно не является узким местом. - person Danica; 21.04.2012