Python 使用多重处理查找阵列中点之间的距离
我一直在尝试使用python的多处理库来加速一个实践项目。在这个项目中,我有两个数组,点和权重,都是x,y坐标。我试图找到每个重量坐标和点之间的距离。当我使用多处理运行程序时,程序使用所有计算机的ram和CPU,当查看task manager时,最多有20个python实例正在运行。我知道这个程序可以运行,因为它不需要多重处理,但需要大约20秒才能完成 下面是代码,底部是使用Pool.map和多处理库中的Process运行的编程Python 使用多重处理查找阵列中点之间的距离,python,multiprocessing,python-multiprocessing,Python,Multiprocessing,Python Multiprocessing,我一直在尝试使用python的多处理库来加速一个实践项目。在这个项目中,我有两个数组,点和权重,都是x,y坐标。我试图找到每个重量坐标和点之间的距离。当我使用多处理运行程序时,程序使用所有计算机的ram和CPU,当查看task manager时,最多有20个python实例正在运行。我知道这个程序可以运行,因为它不需要多重处理,但需要大约20秒才能完成 下面是代码,底部是使用Pool.map和多处理库中的Process运行的编程 import math import random import
import math
import random
import multiprocessing as mp
screenSize = 1000000
pointsLength = 2000
weightLength = 20000
weightBuffer = screenSize/weightLength
pointBuffer = screenSize/pointsLength
points = []
weights = []
weightPoints = []
counter = 0
for i in range(pointsLength):
for j in range(pointsLength):
points.append([random.randint(j * pointBuffer, j * pointBuffer * 2),
random.randint(i * pointBuffer, i * pointBuffer * 2)])
for i in range(pointsLength):
for j in range(pointsLength):
weightPoints.append([j * weightBuffer, i * weightBuffer])
weights.append(0)
def FindDistance(i):
row = math.floor((i / weightLength) / (weightLength / pointsLength))
col = math.floor((i % weightLength) / (weightLength / pointsLength))
points1d = (pointsLength * row) + col
dist = math.dist(points[points1d], weightPoints[i])
weights[i] = dist
# With Multiprocessing Pool
# sumthing = []
# for i in range(len(weights)):
# sumthing.append(i)
# with mp.Pool(4) as p:
# p.map(FindDistance, sumthing)
# With Multiproessing Process
processes = []
for i in range(len(weights)):
p = mp.Process(target=FindDistance, args=[i])
p.start()
processes.append(p)
for process in processes:
process.join()
# Without Multiprocessing
# for i in range(len(weights)):
# FindDistance(i)
# counter += 1
# if (counter % 25000 == 0):
# print(counter / 25000)
如果有人知道我如何使多处理工作,程序将使用我计算机上的8个内核,而不会因为ram或cpu限制而使程序崩溃。您正在迭代权重长度(根据代码为2000),并为每次迭代生成一个新进程,这意味着2000个进程。 难怪CPU和RAM都满了 您需要做的是将权重数组分块成8个较小的数组,最好长度相等。更改FindInstance函数以将数组作为参数。此参数将是较小的分块数组
def FindDistance(i_arr):
for i in i_arr:
row = math.floor((i / weightLength) / (weightLength / pointsLength))
col = math.floor((i % weightLength) / (weightLength / pointsLength))
points1d = (pointsLength * row) + col
dist = math.dist(points[points1d], weightPoints[i])
weights[i] = dist
def chunking(weights):
# initialise array of empty arrays with Length equal to number of processors
smaller_chunks = [ [] i for i in range(8) ]
for index,item in enumerate(weights):
index_to_push = index % 8
smaller_chunks[index_to_push].append(item)
return smaller_chunks
processes = []
chunks = chunking(weights)
for i in range(len(chunks)):
p = mp.Process(target=FindDistance, args=[i])
p.start()
processes.append(p)
for process in processes:
process.join()
问题在于,在
权重的长度上循环。从你的代码中选择哪个
for i in range(pointsLength): #pointsLength is 2000
for j in range(pointsLength):
weightPoints.append([j * weightBuffer, i * weightBuffer])
weights.append(0)
是2000*2000=40000吗
因此,您试图同时创建40000个新进程,导致系统崩溃。
相反,您可以将权重列表分解为n
较小的数组,并使用这些数组创建n
新流程
我们可以使用numpy函数numpy.array\u split
拆分数组。
现在更新FindDistance
函数以接受整个新数组作为输入
def FindDistance(subarr):
for i in subarr:
row = math.floor((i / weightLength) / (weightLength / pointsLength))
col = math.floor((i % weightLength) / (weightLength / pointsLength))
points1d = (pointsLength * row) + col
dist = math.dist(points[points1d], weightPoints[i])
weights[i] = dist
最后用新参数创建n
进程
subarrays = np.array_split(weights, n)
processes = []
for subarr in subarrays:
p = mp.Process(target=FindDistance, args=[subarr])
p.start()
processes.append(p)
for process in processes:
process.join()
问题是你没有正确地进行多重处理。具体来说,您的代码缺少如果uuuu name_uuuuuu=='\uuuuu main\uuuuuuu':
保护。下面的代码使用了多处理.Pool
(我认为这是做你想做的事情的最好、最简单的方法)来解决这个问题。它仍然需要几秒钟的时间来执行,但它不会占用内存和CPU
如果uuu name uuu=='uuuu main uuu':
需要的信息隐藏在多处理
模块文档部分的主模块的安全导入小节中
import math
import random
import multiprocessing as mp
screenSize = 1000000
pointsLength = 2000
weightLength = 20000
weightBuffer = screenSize/weightLength
pointBuffer = screenSize/pointsLength
points = []
weights = []
weightPoints = []
counter = 0
for i in range(pointsLength):
for j in range(pointsLength):
points.append([random.randint(j * pointBuffer, j * pointBuffer * 2),
random.randint(i * pointBuffer, i * pointBuffer * 2)])
for i in range(pointsLength):
for j in range(pointsLength):
weightPoints.append([j * weightBuffer, i * weightBuffer])
weights.append(0)
def FindDistance(i):
row = math.floor((i / weightLength) / (weightLength / pointsLength))
col = math.floor((i % weightLength) / (weightLength / pointsLength))
points1d = (pointsLength * row) + col
dist = math.dist(points[points1d], weightPoints[i])
weights[i] = dist
if __name__ == '__main__': # ADDED
# With Multiprocessing Pool
sumthing = []
for i in range(len(weights)):
sumthing.append(i)
with mp.Pool(4) as p:
p.map(FindDistance, sumthing)
当前程序如何不工作?当我运行该程序时,它会冻结,因为所有的ram和cpu电源都已用完。我尝试使用您的代码,并输入了屏幕大小、pointsLength、weightLength的值100000、1000、5000。我使用您提供的和未提供的多处理代码运行代码。使用多处理代码时,程序需要104秒才能完成,没有代码时仅需48秒。我不确定这是为什么,任务栏显示了类似的ram和cpu使用情况,不同于占用多个python实例的多处理。代码中是否仍然存在错误,或者这个问题不是多处理可以解决的。应该有多达5个Python实例同时运行。我并不惊讶它需要更长的时间。目前,我的答案中的代码只是您自己修改的,足以防止程序冻结,但是由于它在多处理方面的工作方式,它非常低效,并且不能产生可用的结果-即每个进程在其自己的内存空间中运行,因此没有他们都可以访问的共享全局内存。这意味着每个子流程都会创建(并初始化)自己单独的点
、权重
和权重点
列表。明天上午我将进一步讨论。通过Python的多处理
模块,所做工作的速度是无法提高的,这涉及到太多的开销。有这么多的原因是因为必须创建一个单独的操作系统级进程来运行一个几乎微不足道的函数,以计算共享列表中的单个值。除此之外,该函数还使用另外两个非常大的共享列表中的两个值来计算值,这些值必须在每个子进程内重新创建,或者在所有子进程之间共享,这两个值都会带来巨大的开销。通过使finddInstance()
函数在调用时不仅仅计算一个值,因此不需要经常调用它,这将至少减少一些开销,从而可以加快速度。