python - Python 中的并行启动进程串行执行?

标签 python parallel-processing python-3.x multiprocessing

我有一个关于 Python 多处理库的理解问题:
为什么不同的进程(几乎)同时启动,至少看起来是串行执行而不是并行执行?

任务是控制大量粒子(粒子是一组 x/y/z 坐标和质量)的宇宙,并在利用多处理器环境的同时对它们执行各种分析。具体来说,对于下面所示的示例,我想计算所有粒子的质心。
因为该任务明确要求使用多个处理器,所以我没有使用线程库,因为有一个 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 调试器单步执行程序时,我可以看到程序如何总是等待一个进程终止,然后在标记有以“为什么?”结尾的注释的行处启动下一个进程。当然,这可能只是调试器,但是当我查看正常运行中产生的输出时,这完全显示了上面的图片。

  • 这些进程是否并行执行,但由于标准输出的某些共享问题而我看不到它?
  • 如果进程串行执行:为什么?我怎样才能让它们并行运行?

非常感谢任何有助于理解这一点的帮助。

我在配备双核 Intel 处理器的 Windows 7 计算机上使用 Python 3.2.3 从 PyDev 和命令行执行了上述代码。


编辑:
由于程序的输出,我误解了这个问题:进程实际上是并行运行的,但是腌制大量数据并将其发送到子进程的开销花费了很长时间,以至于完全扭曲了图片。
将粒子(即数据)的创建移至子流程,这样它们就不必首先被腌制,从而消除了所有问题并导致程序的有用的并行执行。
为了解决这个任务,我必须将粒子保留在共享内存中,这样它们就不必传递给子进程。

最佳答案

我在我的系统(Python 2.6.5)上运行了你的代码,它几乎立即返回结果,这让我认为你的任务规模可能太小,以至于进程在下一个进程开始之前完成(请注意,启动一个进程比旋转线程慢)。我对结果中使用的总时间 4.7220001220703125 秒表示怀疑,因为这比我的系统运行相同代码所需的时间长了大约 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')

这更符合我的预期。如果增加任务大小,您会得到什么?

关于python - Python 中的并行启动进程串行执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10886036/

相关文章:

python - 通过 python 使用 selenium 和 webdriver 执行测试对网络有任何影响吗?

python - 生成用于测试的空白响应对象

python - 为什么我在这里收到 UnicodeDecodeError ?

python - Numpy 逐 block 减少操作

javascript - 异步运行两个 Promise,但优先考虑第一个 Promise 的结果

algorithm - 并行算法分析

Python 多处理程序未运行到最后

python - 读取 csv 时加快日期时间格式化速度

python-3.x - 无法使用 fastai 的 pretrained_model=URLs.WT103

python - JSON python错误: Expecting value: line 1 column 1 (char 0)