Python 3多处理池

问题描述 投票:3回答:2

我正在学习使用多处理池。我做了这个剧本作为练习。

任何人都可以告诉我为什么使用普通for循环比使用池花费更少的时间?

P.S:我的CPU有2个核心。

非常感谢你。

from multiprocessing import Pool
from functools import reduce
import time

def one(n):
    a = n*n
    return a 

if __name__ == '__main__':
    l = list(range(1000))

    p = Pool()
    t = time.time()
    pol = p.map(one, l)
    result = reduce(lambda x,y: x+y, pol)
    print("Using Pool the result is: ", result, "Time: ", time.time() - t )
    p.close()
    p.join()

    def two(n):
        t = time.time()
        p_result = [] 

        for i in n:
            a = i*i 
            p_result.append(a)

        result = reduce(lambda x,y: x+y, p_result)
        print("Not using Pool the result is: ", result, "Time: ", time.time() - t)

    two(l)

使用池的结果是:332833500时间:0.14810872077941895

不使用池的结果是:332833500时间:0.0005018711090087891

python-3.x multiprocessing pool
2个回答
4
投票

我认为这里有几个原因,但我猜它主要与运行多个进程的开销有关,这主要与同步和通信有关,以及你的非并行化代码是写得更有效率。

作为基础,以下是您的未修改代码在我的计算机上运行的方式:

('Using Pool the result is: ', 332833500, 'Time: ', 0.0009129047393798828)
('Not using Pool the result is: ', 332833500, 'Time: ', 0.000598907470703125)

首先,我想尝试通过使two()函数的代码与并行化代码几乎相同来平衡竞争场。这是修改后的two()函数:

def two(l):
    t = time.time()

    p_result = map(one, l)

    result = reduce(lambda x,y: x+y, p_result)
    print("Not using Pool the result is: ", result, "Time: ", time.time() - t)

现在,在这种情况下,这实际上并没有太大的区别,但是在一秒钟内看到两个案例都做同样的事情将是很重要的。以下是此更改的示例输出:

('Using Pool the result is: ', 332833500, 'Time: ', 0.0009338855743408203)
('Not using Pool the result is: ', 332833500, 'Time: ', 0.0006031990051269531)

我现在要说明的是,由于one()函数的计算成本非常低廉,因此进程间通信的开销超过了并行运行它的好处。我将修改one()函数如下强制它做一堆额外的计算。请注意,由于two()函数的更改,此更改将影响并行和单线程代码。

def one(n):
    for i in range(100000):
        a = n*n
    return a

for循环的原因是为每个进程提供存在的原因。当你有原始代码时,每个进程只进行几次乘法,然后必须将结果列表发送回父进程,并等待给出一个新的块。发送和等待比完成单个块需要更长的时间。通过添加这些额外的周期,它会强制每个块花费更长的时间,而不会改变进程间通信所需的时间,因此我们开始看到并行性得到回报。以下是我使用one()函数更改运行代码时的结果:

('Using Pool the result is: ', 332833500, 'Time: ', 1.861448049545288)
('Not using Pool the result is: ', 332833500, 'Time: ', 3.444211959838867)

所以你有它。您所需要的只是为您的孩子提供更多的工作,而且他们将更有价值。


-1
投票

当使用Pool时,python使用global interpreter lock来同步多个进程之间的多个线程。也就是说,当一个线程正在运行时,所有其他线程都会停止/等待。因此,您将体验到的是顺序执行,而不是并行执行。在您的示例中,即使您在pool中的多个线程之间分发,它们也会由于全局解释器锁而顺序运行。此外,这也增加了调度的大量开销。

从全局解释器锁的python docs:

CPython解释器使用的机制,以确保一次只有一个线程执行Python字节码。这通过使对象模型(包括诸如dict的关键内置类型)对于并发访问而言是隐式安全的,从而简化了CPython实现。锁定整个解释器使得解释器更容易是多线程的,代价是多处理器机器提供的大部分并行性。

因此,你所取得的并不是真正的并行性。如果你需要在python中实现真正的多处理功能,你需要使用Processes,这将导致你使用Queues在进程之间交换数据。


-1
投票

多处理包提供本地和远程并发,通过使用子进程而不是线程有效地侧向执行全局解释器锁。因此,多处理模块允许程序员充分利用给定机器上的多个处理器。

在Python 2.7.16文档的Process-based “threading” interface章节中找到

© www.soinside.com 2019 - 2024. All rights reserved.