2017-02-17 32 views
0

所以我试着在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我用多处理,它仍然较慢。更慢。

+1

https://wiki.python.org/moin/GlobalInterpreterLock – niemmi

+1

另外,你不是多处理,你是multi_threading_。 '多。dummy'只是线程库的一个包装。 https://docs.python.org/2/library/multiprocessing.html#module-multiprocessing.dummy。这就是GIL与此相关的原因。 –

+0

@niemmi嗯,但这是我创建的一个过程,而不是一个线程。纠正我,如果我错了。 GIL在您创建多个线程时适用。就我所知,多个进程可以在python中使用多个内核。 – Rishabh

回答

1

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

+0

嗯,是的,你是正确的在这里设置线程的开销,这也是我最初的想法。但后来我想在这里创建多个使用多个CPU核心的进程,因为我的任务是一个CPU绑定任务。所以这不是一个糟糕的用例,但是你的观点是正确的。 – Rishabh

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 --- 

所以它不是那么清楚一方或另一方是否更快。但是如果你想做多处理,你必须考虑创建线程的开销实际上是否比你期望的更快。你碰到缓存局部性问题等。

+0

请检查我的编辑。 – Rishabh

+0

我看到您的评论,我也做了一个编辑,因为您需要为每个线程解决一个足够大的问题。计算x * x并不是一个足够大的问题。 – CodeMonkey

相关问题