2011-11-01 4 views
2

次の()関数が多少高価で、呼び出しを並列化しようとしているジェネレータがあるとします。私はどこでパラレル化をスローしますか?もう少し具体的にpython generator:ジェネレータ全体を並列に展開する

、この例を考えてみます。

# 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) 

最も基本的なものは、並列化を行い何かに第2ラインを変更することです。いくつかのジェネレータマジックは、ジェネレータ(3番目のライン)を並列にアンパックできるようにしていますか?並行してを次に()と呼んでいますか?

+0

一般的に、私はこれを控えるでしょう。 interalの腸は、非常にステートフルであり、スレッドが危険です。代わりにジェネレータ自体を改善することを検討してください(単純なジェネレータ式ではないが、それを行うには関連するコードでスレッドセーフティが必要な場合でも)。 – delnan

+0

私はあなたの答えに解決策を挙げたと思います。 'block_parser'への呼び出しを並列化します。 – agf

答えて

4

いいえ。自明でないジェネレータの次の状態が現在の状態によって決まるため、next()を順番に呼び出す必要があります。

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

それが価値を生み出す各ポイントでその状態を知らずに上記発電機への呼び出しを並列化する方法はありません。しかし、あなたがそれを知っていれば、それを実行する必要はありません。並列に実行されるようにblock_parser(b)への呼び出しを想定すると、あなたはmultiprocessing.Poolを使用して試みることができる

+0

ありがとうございました...私は推測していましたが、「些細な」ジェネレータ、つまり実際に__next __()に依存しない「固定」ジェネレータで何かを行う方法があるかどうかはわかりませんでした。 – mathtick

+0

リストを反復する単純なものは並列化することができます(実際には、リストを分割してスレッドごとに繰り返し処理します)*しかし、それらは生成するものではありません。それらを並列化する。 – kindall

+0

ここでは、自明ではなく、「高速」ではない独立したものを意味します。おそらく、このトリックはジェネレータを使わないだけです。なぜなら、私は「国家」の概念を必要としない、または望んでいないからです...私は、仕事とargsへのインデックスが必要です。 – mathtick

2

import multiprocessing as mp 

pool = mp.Pool() 

raw_blocks = (b for b in 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.Queueを通してmp.Pool転送タスクと結果ためpickableなければなりません。
+0

ええ、私は確かにmp.Poolを使用します。私はジェネレータについて質問していた概念的な質問に答えるので、他の答えを「正しい」とマークしますが、これはあなたが提供した良い解決策です。 – mathtick

関連する問題