python中的多处理以加速函数
我对Python多处理感到困惑 我试图加快处理数据库字符串的函数的速度,但我一定误解了多处理的工作原理,因为将该函数提供给一个工作池比“正常处理”花费的时间更长 这里有一个我正在努力实现的例子python中的多处理以加速函数,python,windows,map,multiprocessing,Python,Windows,Map,Multiprocessing,我对Python多处理感到困惑 我试图加快处理数据库字符串的函数的速度,但我一定误解了多处理的工作原理,因为将该函数提供给一个工作池比“正常处理”花费的时间更长 这里有一个我正在努力实现的例子 from time import clock, time from multiprocessing import Pool, freeze_support from random import choice def foo(x): TupWerteMany = [] for i in
from time import clock, time
from multiprocessing import Pool, freeze_support
from random import choice
def foo(x):
TupWerteMany = []
for i in range(0,len(x)):
TupWerte = []
s = list(x[i][3])
NewValue = choice(s)+choice(s)+choice(s)+choice(s)
TupWerte.append(NewValue)
TupWerte = tuple(TupWerte)
TupWerteMany.append(TupWerte)
return TupWerteMany
if __name__ == '__main__':
start_time = time()
List = [(u'1', u'aa', u'Jacob', u'Emily'),
(u'2', u'bb', u'Ethan', u'Kayla')]
List1 = List*1000000
# METHOD 1 : NORMAL (takes 20 seconds)
x2 = foo(List1)
print x2[1:3]
# METHOD 2 : APPLY_ASYNC (takes 28 seconds)
# pool = Pool(4)
# Werte = pool.apply_async(foo, args=(List1,))
# x2 = Werte.get()
# print '--------'
# print x2[1:3]
# print '--------'
# METHOD 3: MAP (!! DOES NOT WORK !!)
# pool = Pool(4)
# Werte = pool.map(foo, args=(List1,))
# x2 = Werte.get()
# print '--------'
# print x2[1:3]
# print '--------'
print 'Time Elaspse: ', time() - start_time
我的问题是:
因此,您的第一个问题是在
foo(x)
中没有实际的并行性,您只需将整个列表传递给函数一次
(一)
进程池的概念是让许多进程在某些数据的独立位上进行计算
# METHOD 2 : APPLY_ASYNC
jobs = 4
size = len(List1)
pool = Pool(4)
results = []
# split the list into 4 equally sized chunks and submit those to the pool
heads = range(size/jobs, size, size/jobs) + [size]
tails = range(0,size,size/jobs)
for tail,head in zip(tails, heads):
werte = pool.apply_async(foo, args=(List1[tail:head],))
results.append(werte)
pool.close()
pool.join() # wait for the pool to be done
for result in results:
werte = result.get() # get the return value from the sub jobs
如果处理每个块所需的时间大于启动流程所需的时间,那么这只会给您带来实际的加速,在有四个流程和四个作业要完成的情况下,当然,如果您有4个流程和100个作业要完成,这些动态会发生变化。请记住,您四次创建一个全新的python解释器,这不是免费的
2) map的问题是,它在一个单独的过程中将foo
应用于List1
中的每个元素,这将花费相当长的时间。因此,如果您的池有4个进程map
将弹出列表中的一项四次,并将其发送给要处理的进程-等待进程完成-弹出列表中的更多内容-等待进程完成。只有当处理单个项目需要很长时间时,这才有意义,例如,如果每个项目都是指向1GB文本文件的文件名。但目前,map只需要获取列表的单个字符串,并将其传递给foo
,其中asapply\u async
获取列表的一部分。请尝试以下代码
def foo(thing):
print thing
map(foo, ['a','b','c','d'])
这是内置的python映射,将运行单个进程,但多进程版本的想法完全相同
根据J.F.Sebastian的评论添加:但是,您可以使用chunksize
参数来map
为每个块指定大约的大小
pool.map(foo, List1, chunksize=size/jobs)
不过我不知道Windows上的map
是否有问题,因为我没有可供测试的映射
3) 是的,考虑到您的问题已经足够大,有理由推出新的python解释器
4) 不能给你一个明确的答案,因为这取决于内核/处理器的数量等。但一般来说,在Windows上应该可以。如果你感兴趣,这里有一个通用的多处理模板
import multiprocessing as mp
import time
def worker(x):
time.sleep(0.2)
print "x= %s, x squared = %s" % (x, x*x)
return x*x
def apply_async():
pool = mp.Pool()
for i in range(100):
pool.apply_async(worker, args = (i, ))
pool.close()
pool.join()
if __name__ == '__main__':
apply_async()
输出如下所示:
x= 0, x squared = 0
x= 1, x squared = 1
x= 2, x squared = 4
x= 3, x squared = 9
x= 4, x squared = 16
x= 6, x squared = 36
x= 5, x squared = 25
x= 7, x squared = 49
x= 8, x squared = 64
x= 10, x squared = 100
x= 11, x squared = 121
x= 9, x squared = 81
x= 12, x squared = 144
正如您所看到的,这些数字不是按顺序排列的,因为它们是异步执行的。关于问题(2)
在Dougal和Matti的指导下,我找到了问题所在。
原始的foo函数处理列表列表,而map需要一个函数来处理单个元素
新功能应该是
def foo2 (x):
TupWerte = []
s = list(x[3])
NewValue = choice(s)+choice(s)+choice(s)+choice(s)
TupWerte.append(NewValue)
TupWerte = tuple(TupWerte)
return TupWerte
以及称之为:
感谢所有帮助我理解这一点的人
所有方法的结果:
对于List*2 Mio记录:正常13.3秒,与异步并行7.5秒,与chunksize:7.3的map并行,不带chunksize 5.2秒(1)已被多次提及,简短的故事是并发并不是一种神奇的更快的方法,它有开销,还受到处理器数量和操作系统可以释放多少资源的限制。我想去搜索一个链接,但是这些东西很难搜索。谢谢Delnan。请相信我在提出问题之前已经进行了广泛的搜索。我理解你的观点,但希望有人能对这一特殊情况有一个“具体”的答案。@user1043144:当你改变池中进程的数量时,时间是如何变化的?实际上没有区别。我一定是在什么地方弄错了。你的
地图不起作用的原因是你的论点错了;没有args
参数。它应该是pool.map(foo,List1)
(就像bultinmap
),但是foo
实际上需要一个列表。您应该将foo
更改为仅内部循环部分,或者执行类似于pool.map(foo,(对于xrange中的i(len(List1),None,None,10))的操作
。此外,对于成本不高的较小的sof操作集,设置多处理功能的开销比您获得的任何加速都要大。这只是我创建的一个示例。我的实际问题涉及大量数据集。pool.map
不会每次启动一个新进程;它会重用这四个进程(或多个)由池创建的。但是,它每次都会对参数进行pickle/unpickle处理。我从来没有说过它会启动新的process@user1043144如果你的意思是“uuuGe”,你可能想考虑不要在主进程中加载数据,但是在<代码> fo中,你可以使用<代码> MMAP>代码>只加载文件的那一部分。这实际上是需要的。加载和传递所有这些数据也会让你付出代价,因此,根据数据量的大小,可能也会有一些显著的节省。这与问题有什么关系?文档中也可以找到一个通用的mp
模板?b/c他们甚至没有以正确的方式使用多处理问:这是一个正确的方法,海报可以使用它来正确地重写它们的功能。
jobs = 4
size = len(List1)
pool = Pool()
#Werte = pool.map(foo2, List1, chunksize=size/jobs)
Werte = pool.map(foo2, List1)
pool.close()
print Werte[1:3]