2

Python のマルチプロセッシング ライブラリに関する理解の問題/質問があります:
異なるプロセスが (ほぼ) 同時に開始されたのはなぜですか?

タスクは、多数の粒子 (粒子は x/y/z 座標と質量のセット) の宇宙を制御し、マルチプロセッサ環境を利用しながら、それらに対してさまざまな分析を実行することです。具体的には、以下に示す例では、すべての粒子の重心を計算したいと考えています。
タスクでは複数のプロセッサを使用するように具体的に指示されているため、スレッド ライブラリは使用しませんでした。これは、実行を 1 つのプロセッサに制限する GIL が配置されているためです。
これが私のコードです:

from multiprocessing import Process, Lock, Array, Value
from random import random
import math
from time import time

def exercise2(noOfParticles, noOfProcs):
    startingTime = time()
    particles = []
    processes = []
    centerCoords = Array('d',[0,0,0])
    totalMass = Value('d',0)
    lock = Lock()

    #create all particles
    for i in range(noOfParticles):
        p = Particle()
        particles.append(p)

    for i in range(noOfProcs):
        #determine the number of particles every process needs to analyse
        particlesPerProcess = math.ceil(noOfParticles / noOfProcs)
        #create noOfProcs Processes, each with a different set of particles        
        p = Process(target=processBatch, args=(
            particles[i*particlesPerProcess:(i+1)*particlesPerProcess],
            centerCoords, #handle to shared memory
            totalMass, #handle to shared memory
            lock, #handle to lock
            'batch'+str(i)), #also pass name of process for easier logging
            name='batch'+str(i))
        processes.append(p)
        print('created proc:',i)

    #start all processes
    for p in processes:
        p.start() #here, the program waits for the started process to terminate. why?

    #wait for all processes to finish
    for p in processes:
        p.join()

    #normalize the coordinates
    centerCoords[0] /= totalMass.value
    centerCoords[1] /= totalMass.value
    centerCoords[2] /= totalMass.value

    print(centerCoords[:])
    print('total time used', time() - startingTime, ' seconds')


class Particle():
    """a particle is a very simple physical object, having a set of x/y/z coordinates and a mass.
    All values are randomly set at initialization of the object"""

    def __init__(self):
        self.x = random() * 1000
        self.y = random() * 1000
        self.z = random() * 1000
        self.m = random() * 10

    def printProperties(self):
        attrs = vars(self)
        print ('\n'.join("%s: %s" % item for item in attrs.items()))

def processBatch(particles,centerCoords,totalMass,lock,name):
    """calculates the mass-weighted sum of all coordinates of all particles as well as the sum of all masses.
    Writes the results into the shared memory centerCoords and totalMass, using lock"""

    print(name,' started')
    mass = 0
    centerX = 0
    centerY = 0
    centerZ = 0

    for p in particles:
        centerX += p.m*p.x
        centerY += p.m*p.y
        centerZ += p.m*p.z
        mass += p.m

    with lock:
        centerCoords[0] += centerX
        centerCoords[1] += centerY
        centerCoords[2] += centerZ
        totalMass.value += mass

    print(name,' ended')

if __name__ == '__main__':
    exercise2(2**16,6)

ここで、すべてのプロセスがほぼ同時に開始され、並行して実行されることを期待しています。しかし、プログラムの出力を見ると、プロセスが連続して実行されているように見えます。

created proc: 0
created proc: 1
created proc: 2
created proc: 3
created proc: 4
created proc: 5
batch0  started
batch0  ended
batch1  started
batch1  ended
batch2  started
batch2  ended
batch3  started
batch3  ended
batch4  started
batch4  ended
batch5  started
batch5  ended
[499.72234074100135, 497.26586187539453, 498.9208784328791]
total time used 4.7220001220703125  seconds

また、Eclipse デバッガーを使用してプログラムをステップ実行すると、'why?' で終わるコメントでマークされた行で、プログラムが常に 1 つのプロセスが終了するのを待ってから、次のプロセスを開始することがわかります。もちろん、これは単なるデバッガかもしれませんが、通常の実行で生成された出力を見ると、これはまさに上の図を示しています。

  • これらのプロセスは並行して実行されていますが、stdout の共有の問題が原因でそれを見ることができませんか?
  • プロセスが連続して実行されている場合: なぜですか? また、それらを並行して実行するにはどうすればよいですか?

これを理解するための助けは大歓迎です。

デュアル コア Intel プロセッサを搭載した Windows 7 マシンで Python 3.2.3 を使用して、PyDev およびコマンド ラインから上記のコードを実行しました。


編集:
プログラムの出力のために、私は問題を誤解しました: プロセスは実際には並行して実行されていますが、大量のデータをピクルしてサブプロセスに送信するオーバーヘッドが非常に長くなり、画像が完全に歪んでしまいます。
パーティクル (つまりデータ) の作成をサブプロセスに移動して、そもそもピクルする必要がないようにすることで、すべての問題が取り除かれ、プログラムの便利な並列実行が実現しました。
したがって、タスクを解決するには、サブプロセスに渡す必要がないように、パーティクルを共有メモリに保持する必要があります。

4

1 に答える 1

2

私のシステム (Python 2.6.5) でコードを実行したところ、ほぼ瞬時に結果が返されました。おそらく、タスクのサイズが小さすぎて、次のプロセスが開始される前にプロセスが終了していると思われます (プロセスの開始は遅いことに注意してください)。スレッドをスピンアップするよりも)。total time used 4.7220001220703125 seconds私のシステムが同じコードを実行するのにかかった時間よりも約 40 倍長いので、あなたの結果について質問します。パーティクルの数を にスケールアップした2**20ところ、次の結果が得られました。

('created proc:', 0)
('created proc:', 1)
('created proc:', 2)
('created proc:', 3)
('created proc:', 4)
('created proc:', 5)
('batch0', ' started')
('batch1', ' started')
('batch2', ' started')
('batch3', ' started')
('batch4', ' started')
('batch5', ' started')
('batch0', ' ended')
('batch1', ' ended')
('batch2', ' ended')
('batch3', ' ended')
('batch5', ' ended')
('batch4', ' ended')
[500.12090773656854, 499.92759577086059, 499.97075039983588]
('total time used', 5.1031057834625244, ' seconds')

それは私が期待するものとより一致しています。タスクのサイズを大きくするとどうなりますか?

于 2012-06-04T18:53:39.653 に答える