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