我有一个数字列表。我想对列表中的每个数字执行一些耗时的操作,并创建一个包含所有结果的新列表。这是我所拥有的简化版本:
def calcNum(n):#some arbitrary, time-consuming calculation on a number
m = n
for i in range(5000000):
m += i%25
if m > n*n:
m /= 2
return m
nums = [12,25,76,38,8,2,5]
finList = []
for i in nums:
return_val = calcNum(i)
finList.append(return_val)
print(finList)
现在,我想利用我的CPU中的多个核心,并给每个核心处理其中一个数字的任务,并且由于“数字计算”功能从头到尾是自包含的,我想这样做很简单,也是多处理/线程的完美情况。
我的问题是,我应该使用哪一种(多处理或线程化?),以及最简单的方法是什么?
我使用我在其他问题中找到的各种代码进行了测试来实现这一点,虽然它运行良好但它似乎没有进行任何实际的多线程/处理并且需要与我的第一次测试一样长:
from multiprocessing.pool import ThreadPool
def calcNum(n):#some arbitrary, time-consuming calculation on a number
m = n
for i in range(5000000):
m += i%25
if m > n*n:
m /= 2
return m
pool = ThreadPool(processes=3)
nums = [12,25,76,38,8,2,5]
finList = []
for i in nums:
async_result = pool.apply_async(calcNum, (i,))
return_val = async_result.get()
finList.append(return_val)
print(finList)
答案 0 :(得分:4)
multiprocessing.pool
和pool.map
是您最好的朋友。它隐藏了很多头痛,因为它隐藏了所有其他复杂的队列,以及你需要做些什么来使它工作。您需要做的就是设置池,为其分配最大进程数,将其指向函数并进行迭代。请参阅下面的工作代码
由于join
和用例pool.map
旨在起作用,程序将等到所有进程都返回一些内容之后再提供结果。
from multiprocessing.pool import Pool
def calcNum(n):#some arbitrary, time-consuming calculation on a number
print "Calcs Started on ", n
m = n
for i in range(5000000):
m += i%25
if m > n*n:
m /= 2
return m
if __name__ == "__main__":
p = Pool(processes=3)
nums = [12,25,76,38,8,2,5]
finList = []
result = p.map(calcNum, nums)
p.close()
p.join()
print result
这会让你得到这样的东西:
Calcs Started on 12
Calcs Started on 25
Calcs Started on 76
Calcs Started on 38
Calcs Started on 8
Calcs Started on 2
Calcs Started on 5
[72, 562, 5123, 1270, 43, 23, 23]
无论每个进程何时启动或何时完成,map都会等待每个进程完成,然后将它们全部放回正确的顺序(对应于输入可迭代)。
正如@Guy所说,GIL在这里伤害了我们。您可以在上面的代码中将Pool
更改为ThreadPool
,看看它如何影响计算的时间。由于使用了相同的函数,GIL一次只允许一个线程使用calcNum
函数。所以它足够接近连续运行。
带有Multirocessing
或process
的{{1}}实际上会启动脚本的更多实例,以解决GIL问题。如果您在上面的过程中观察正在运行的进程,则会在池运行时看到“python.exe”的额外实例。在这种情况下,您将看到总共4个。
答案 1 :(得分:0)
我猜你受到了Global Interpreter Lock
的影响GIL存在争议,因为它可以防止多线程CPython程序在某些情况下充分利用多处理器系统。
尝试使用multiprocessing代替
from multiprocessing import Pool