我尝试编写一个用于多处理的python。我一直在网上阅读,但我仍然不明白如何写它。
我的剧本:
import multiprocessing as mp
import numpy as np
import ctypes
def func(M, j, :
coor_i = np.zeros(1000)
coor_j = np.ones(1000) # In reality it is loaded from a txt
A = np.square(coor_i - coor_j)
a = A.sum
M[j] = a
for i in range(1,100) :
M = mp.Array(ctypes.c_double, np.ones(i))
p = mp.Process(target = func, args = (coor_i, j)) for j in range(1,i)
p.start()
p.join()
print(M)
我在线看,我看过 - 'mp.Pool','过程','mp.Queue'
非常感谢。
答案 0 :(得分:0)
首先,您的第一个错误是不从您的func()
函数返回任何内容。在python中,所有值都是对内存中对象的引用,当您执行赋值时,您将使用新对象替换引用的值。因此,M = -M
不会改变M
的对象,而是创建一个新对象,并在函数范围内更改引用M
。
这意味着您的功能总是返回None
:
>>> from multiprocessing import Pool
>>> def func(M): # if you call with M=1
... # M==1 here
... M = -M
... # M==-1 here
...
>>> M = 1
>>> M = func(M)
>>> print(M)
None
要解决此问题,您需要将返回值:
>>> def func(M):
... return -M
...
>>> print(func(1))
-1
然后,并行化工作的最佳方法是使用一个进程池,以便您可以控制并行运行的实例数,直接调整from the documentation examples:
>>> def func(M):
>>> return -M
...
>>> pool = Pool(processes=4) # start 4 worker processes
>>> results = []
>>> for i in range(1,100):
... results.append(pool.apply_async(func, [i])) # evaluate "func(i)" asynchronously
...
>>> print [result.get() for result in results]
[-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -35, -36, -37, -38, -39, -40, -41, -42, -43, -44, -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -57, -58, -59, -60, -61, -62, -63, -64, -65, -66, -67, -68, -69, -70, -71, -72, -73, -74, -75, -76, -77, -78, -79, -80, -81, -82, -83, -84, -85, -86, -87, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99]
另一种做同样事情的方法是使用:
>>> print(pool.map(func, range(1,100)))
[-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -35, -36, -37, -38, -39, -40, -41, -42, -43, -44, -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -57, -58, -59, -60, -61, -62, -63, -64, -65, -66, -67, -68, -69, -70, -71, -72, -73, -74, -75, -76, -77, -78, -79, -80, -81, -82, -83, -84, -85, -86, -87, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99]
话虽如此,如果你所做的一切确实是在否定价值(或者那些简单的东西) - 我猜你不是 - 那么 NOT 最好使用并行化, python和你的微处理器将矢量化工作并让它运行得更快:
>>> print([-M for M in range(1,100)])
[-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -35, -36, -37, -38, -39, -40, -41, -42, -43, -44, -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -57, -58, -59, -60, -61, -62, -63, -64, -65, -66, -67, -68, -69, -70, -71, -72, -73, -74, -75, -76, -77, -78, -79, -80, -81, -82, -83, -84, -85, -86, -87, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99]
这是一个指标,在我的机器上用python2运行:
>>> from timeit import timeit
>>> timeit("[-M for M in range(1,100)]", number=100000)
0.6327948570251465
>>> def test():
... pool.map(func, range(1,100))
...
>>> timeit(test, number=100000)
31.26303195953369
编辑:
你的问题的问题在于,你不清楚你想要实现什么,以及你想要做什么。通常,并行化的第一个途径是执行非并行化的版本,并尝试并行化更好地工作并且没有互斥的事物。
但是在你的代码中让我感到震惊的是,对于range(1,100)
循环的每次迭代,你实际上都在等待一个进程完成,然后再启动一个进程:
for i in range(1,100) :
M = mp.Array(ctypes.c_double, np.ones(i))
# Create process
p = mp.Process(target = func, args = (coor_i, j)) for j in range(1,i)
# Start a process
p.start()
# wait for the process p to finish before going on
p.join()
# will continue when p has finished
如果您想解决此问题,可以使用我的示例中显示的Pool
或:
for i in range(1,100) :
M = mp.Array(ctypes.c_double, np.ones(i))
# Create process
p = mp.Process(target = func, args = (coor_i, j)) for j in range(1,i)
# Start a process
p.start()
# wait for the process p to finish before going on
p.join()
# will continue when p has finished
因此,快速改进将是:
processes = [] # keep a list of all the processes
for i in range(1,100) :
M = mp.Array(ctypes.c_double, np.ones(i))
# Create process
for j in range(1,i):
p = mp.Process(target = func, args = (coor_i, j))
# Append to processes list
processes.append(p)
# Start a process
p.start()
# wait for all processes to have finished before quitting (or going on)
for p in processes:
p.join()
所以我刚刚更新了代码:你在一个循环中启动所有进程,而在另一个循环中你阻塞直到它们完成。 .join()
正在阻止当前进程阻塞,直到另一个进程完成,因此第二个循环确保每个进程在完成代码片段之前已完成,或继续执行更多代码。
因此,对于“生成器”问题,我没有注意到您在for j in range(1, i)
行上执行了mp.Process
,因此没有将进程附加到进程列表,而是添加了列表生成器。 / p>
实际情况是你的conde 无法工作,并且在编译时会失败,因为:
p = Process(target = func, args = (coor_i, j)) for j in range(1 ,i)
^
SyntaxError: invalid syntax
如果您通过以下方式更正:
>>> (p = Process(target = func, args = (coor_i, j)) for j in range(1 ,i))
然后您的原始代码无法工作,因为p
不是进程,而是列表生成器且p.start()
不存在:
>>> p.next()
<Process(Process-5, initial)>
>>> p.next()
<Process(Process-6, initial)>
>>> p.next()
<Process(Process-7, initial)>
>>> p.next()
<Process(Process-8, initial)>
>>> p.next()
<Process(Process-9, initial)>
因此,在这种情况下使用for one liner不是一个坏主意,而是使用传统方法进行修正。