29

Python のマルチプロセッシング モジュールについて読んでいます。私はまだ、それができることをよく理解しているとは思いません。

クアッドコア プロセッサがあり、1,000,000 個の整数を含むリストがあり、すべての整数の合計が必要だとします。私は簡単に行うことができます:

list_sum = sum(my_list)

しかし、これはそれを1つのコアにしか送信しません。

multiprocessing モジュールを使用して、配列を分割し、各コアにその部分の合計を取得させて値を返すようにして、合計を計算できるようにすることは可能ですか?

何かのようなもの:

core1_sum = sum(my_list[0:500000])          #goes to core 1
core2_sum = sum(my_list[500001:1000000])    #goes to core 2
all_core_sum = core1_sum + core2_sum        #core 3 does final computation

どんな助けでも大歓迎です。

4

3 に答える 3

37

はい、複数のスレッドで行うのと同じように、複数のプロセスでこの合計を行うことができます。

from multiprocessing import Process, Queue

def do_sum(q,l):
    q.put(sum(l))

def main():
    my_list = range(1000000)

    q = Queue()

    p1 = Process(target=do_sum, args=(q,my_list[:500000]))
    p2 = Process(target=do_sum, args=(q,my_list[500000:]))
    p1.start()
    p2.start()
    r1 = q.get()
    r2 = q.get()
    print r1+r2

if __name__=='__main__':
    main()

ただし、複数のプロセスで実行すると、単一のプロセスで実行するよりも遅くなる可能性があります。これは、データをすぐに合計するよりもデータを前後にコピーする方がコストがかかるためです。

于 2009-07-25T15:48:51.047 に答える
22

並行プログラミングの世界へようこそ。

Python ができること (できないこと) は、2 つのことに依存します。

  1. OS でできること (およびできないこと)。ほとんどの OS はプロセスをコアに割り当てます。4 コアを使用するには、問題を 4 つのプロセスに分割する必要があります。これは思ったより簡単です。時々。

  2. 基盤となる C ライブラリでできること (およびできないこと)。C ライブラリが OS の機能を公開し、かつ OS がハードウェアの機能を公開している場合、あなたは堅実です。

特に GNU/Linux では、問題を複数のプロセスに分割するのは簡単です。複数ステップのパイプラインに分割します。

100 万の数を合計する場合は、次のシェル スクリプトを考えてください。sum.py標準入力の数値の範囲または数値のリストのいずれかを合計する架空のプログラムを想定しています。

( sum.py 0 500000 & sum.py 50000 1000000 ) | sum.py

これには、3 つの同時プロセスがあります。2 つは多くの数の合計を計算し、3 つ目は 2 つの数の合計を計算します。

GNU/Linux シェルと OS はすでに並行処理の一部を処理しているため、標準入力から読み取り、標準出力に書き込み、大きなジョブの小さな部分を実行するように設計された単純な (非常に単純な) プログラムを設計できます。

ジョブをシェルに割り当てる代わりに、サブプロセスを使用してパイプラインを構築することで、オーバーヘッドを削減することができます。ただし、シェルがパイプラインを非常に迅速に構築することに気付くかもしれません。(これは C で直接書かれており、直接 OS API 呼び出しを行います。)

于 2009-07-25T15:45:49.867 に答える
8

確かに、例えば:

from multiprocessing import Process, Queue

thelist = range(1000*1000)

def f(q, sublist):
    q.put(sum(sublist))

def main():
    start = 0
    chunk = 500*1000
    queue = Queue()
    NP = 0
    subprocesses = []
    while start < len(thelist):
      p = Process(target=f, args=(queue, thelist[start:start+chunk]))
      NP += 1
      print 'delegated %s:%s to subprocess %s' % (start, start+chunk, NP)
      p.start()
      start += chunk
      subprocesses.append(p)
    total = 0
    for i in range(NP):
      total += queue.get()
    print "total is", total, '=', sum(thelist)
    while subprocesses:
      subprocesses.pop().join()

if __name__ == '__main__':
    main()

結果:

$ python2.6 mup.py 
delegated 0:500000 to subprocess 1
delegated 500000:1000000 to subprocess 2
total is 499999500000 = 499999500000

この粒度は細かすぎて、プロセスを生成する価値がないことに注意してください -- 全体的な合計タスクは小さく (これが、チェックとして main で合計を再計算できる理由です;-) あまりにも多くのデータが前後に移動されています (実際、サブプロセスは作業対象のサブリストのコピーを取得する必要はありません -- インデックスで十分です)。したがって、これはマルチプロセッシングが実際に保証されていない「おもちゃの例」です。ただし、さまざまなアーキテクチャ (キューから実行する複数のタスクを受け取るサブプロセスのプールを使用する、前後のデータ移動を最小限に抑えるなど) を使用し、粒度の低いタスクでは、パフォーマンスの面で実際にメリットを得ることができます。

于 2009-07-25T15:55:45.913 に答える