为什么给定代码中的多处理代码比通常的顺序执行花费更多时间?

时间:2017-02-17 07:14:28

标签: python multiprocessing

所以我尝试在python中进行多处理,并尝试使用这两种技术执行简单的map函数并进行基准测试。然而,奇怪的是,它实际上花了更多的时间在我创建4个池的代码中。以下是我的通用代码:

from datetime import datetime
from multiprocessing.dummy import Pool as ThreadPool
def square(x):
    return x*x

l = xrange(10000000)
map(square, l)

执行此代码需要大约1.5秒

现在我使用以下代码创建了4个用于多处理的池:

from datetime import datetime
from multiprocessing.dummy import Pool as ThreadPool
def square(x):
    return x*x
l = xrange(10000000)
pool = ThreadPool(4) 
results = pool.map(square, l)
pool.close() 
pool.join() 

现在,当我对它进行基准测试时,多处理代码实际上需要更多时间(大约2.5秒)。由于它是一个cpu绑定的任务,我有点困惑,因为它为什么花了更多的时间,它实际应该采取更少。对我做错了什么看法?

编辑 - 而不是multiprocessing.dummy我使用多处理,它仍然较慢。更慢。

2 个答案:

答案 0 :(得分:1)

这并不奇怪。你的测试是一个非常差的测试。您可以将线程用于长时间运行的任务但是你正在测试的是一个几乎立即返回的函数。这里的主要因素是设置线程的开销。这远远超过了线程可能带来的任何好处。

答案 1 :(得分:0)

问题是你正在使用假人。即多线程,而不是多处理。多线程不会使CPU绑定任务更快,但只有I / O绑定任务。

再试一次multiprocessing.Pool,你应该取得更大的成功。

multiprocessing.dummy in Python is not utilising 100% cpu

此外,您需要以某种方式将输入序列组合成子序列,以使每个进程都进行足够的计算以使其值得。

我把它放到一个解决方案中。看到你需要仅在主执行时调用多处理池,问题是Python启动了每个映射的子引擎。

import time
from multiprocessing import Pool as ThreadPool

def square(x):
    return x*x

def squareChunk(chunk):
    return [square(x) for x in chunk]

def chunks(l, n):
    n = max(1, n)
    return (l[i:i+n] for i in range(0, len(l), n))

def flatten(ll):
    lst = []
    for l in ll:
        lst.extend(l)
    return lst

if __name__ == '__main__':
    start_time = time.time()
    r1 = range(10000000)
    nProcesses = 100
    chunked = chunks(r1, int(len(r1)/nProcesses)) #split original list in decent sized chunks
    pool = ThreadPool(4) 
    results = flatten(pool.map(squareChunk, chunked))
    pool.close() 
    pool.join() 
    print("--- Parallel map %g seconds ---" % (time.time() - start_time))

    start_time = time.time()
    r2 = range(10000000)
    squareChunk(r2)
    print("--- Serial map %g seconds ---" % (time.time() - start_time))

我得到以下打印输出:

--- Parallel map 3.71226 seconds ---
--- Serial map 2.33983 seconds ---

现在问题是并行地图不应该更快吗?

可能整个组合花费了我们的效率。但也可能是发动机更加温暖"当串行处理运行之后。所以我转过身来测量:

import time
from multiprocessing import Pool as ThreadPool

def square(x):
    return x*x

def squareChunk(chunk):
    return [square(x) for x in chunk]

def chunks(l, n):
    n = max(1, n)
    return (l[i:i+n] for i in range(0, len(l), n))

def flatten(ll):
    lst = []
    for l in ll:
        lst.extend(l)
    return lst

if __name__ == '__main__':
    start_time = time.time()
    r2 = range(10000000)
    squareChunk(r2)
    print("--- Serial map %g seconds ---" % (time.time() - start_time))

    start_time = time.time()
    r1 = range(10000000)
    nProcesses = 100
    chunked = chunks(r1, int(len(r1)/nProcesses)) #split original list in decent sized chunks
    pool = ThreadPool(4) 
    results = flatten(pool.map(squareChunk, chunked))
    pool.close() 
    pool.join() 
    print("--- Parallel map %g seconds ---" % (time.time() - start_time))

现在我得到了:

--- Serial map 4.176 seconds ---
--- Parallel map 2.68242 seconds ---

所以不清楚一个或另一个是否更快。但是如果你想进行多处理,你必须考虑创建线程的开销实际上是否比加速期望的要小得多。您遇到缓存局部性问题等。