генератор python: распаковать весь генератор параллельно - PullRequest
4 голосов
/ 02 ноября 2011

Предположим, у меня есть генератор, чья функция __next__() несколько дорогая, и я хочу попробовать распараллелить вызовы. Куда мне добавить парализатор?

Чтобы быть более конкретным, рассмотрим пример:

# fast, splitting a file for example
raw_blocks = (b for b in block_generator(fin))
# slow, reading blocks, checking values ...
parsed_blocks = (block_parser(b) for b in raw_blocks)
# get all parsed blocks into a data structure
data = parsedBlocksToOrderedDict(parsed_blocks)

Самое основное - это изменить вторую строку на что-то, что выполняет распараллеливание Есть ли какая-то магия генератора, которая позволяет распаковать линию генератора (на 3-й) параллельно? Вызов __next__() параллельно?

Ответы [ 2 ]

4 голосов
/ 02 ноября 2011

Нет. Вы должны вызывать next() последовательно, потому что следующее состояние любого нетривиального генератора определяется его текущим состоянием.

def gen(num):
    j=0
    for i in xrange(num):
        j += i
        yield j

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

3 голосов
/ 02 ноября 2011

Если предположить, что вызовы block_parser(b) будут выполняться параллельно, вы можете попробовать использовать multiprocessing.Pool :

import multiprocessing as mp

pool = mp.Pool()

raw_blocks = block_generator(fin)
parsed_blocks = pool.imap(block_parser, raw_blocks)
data = parsedBlocksToOrderedDict(parsed_blocks)

Обратите внимание, что:

  • Если вы ожидаете, что list(parsed_blocks) может полностью поместиться в памяти, тогда использование pool.map может быть намного быстрее, чем pool.imap.
  • Элементы в raw_blocks и возвращаемые значения из block_parse должен быть выбираемым, поскольку mp.Pool передает задачи и результаты mp.Queue.
...