Pythons多处理池未并行运行

Pythons多处理池未并行运行,python,parallel-processing,multiprocessing,Python,Parallel Processing,Multiprocessing,我目前正试图计算python中数千个向量到数百万个50维向量的最近邻。让它按顺序运行似乎是一种巨大的时间浪费,所以我想将其并行化 首先,我用pickle加载预处理的数据,其中我有一个dict,其中我的对象p作为键,向量形式(p2v)作为值,还有一些id确定要查看哪些ps。然后我将ID划分为8个块,这样每个进程都必须计算多个p的邻居。find_Nestest_n_chunks方法获取一个ID数组,并在p2v dict中查找向量。然后通过整个dict计算最近邻(在我的测试中,我只查看dict中的10

我目前正试图计算python中数千个向量到数百万个50维向量的最近邻。让它按顺序运行似乎是一种巨大的时间浪费,所以我想将其并行化

首先,我用pickle加载预处理的数据,其中我有一个dict,其中我的对象p作为键,向量形式(p2v)作为值,还有一些id确定要查看哪些ps。然后我将ID划分为8个块,这样每个进程都必须计算多个p的邻居。find_Nestest_n_chunks方法获取一个ID数组,并在p2v dict中查找向量。然后通过整个dict计算最近邻(在我的测试中,我只查看dict中的10个元素)

目前,我在windows计算机上工作,代码如下:

import time
import multiprocessing as mp
import pickle

def find_closest_n_chunks(ids, p2v, n):
    print("starting a chunk")
    neighbors = []
    for p in ids:
        p2distance = {}
        vector = p2v[p]
        for key in list(p2v.keys())[:10]:
            distance = cosine(vector, p2v[key])
            p2distance[key] = distance
        sorted_by_distance = sorted(p2distance.items(), key=lambda kv: kv[1])
        neighbors.append(sorted_by_distance[:n])
    print("finished chunk")
    return neighbors

if __name__ == '__main__':
    file = open('./prelim_results/DataHandlerC08.obj', "rb")
    handler = pickle.load(file)
    file = open("./prelim_results/vectorsC08.obj", "rb")
    p2v = pickle.load(file)
    ids = handler.evaluation_ids

    chunks = []
    chunk_p2v = []
    for _ in range(8):
        chunks.append([])
        chunk_p2v.append(p2v.copy())
    for idx, p in enumerate(ids):
        array_idx = idx % 8
        chunks[array_idx].append(p)
    print("starting")
    start = time.time()
    with mp.Pool(processes=8, maxtasksperchild=1) as pool:
        results = []
        for idx, chunk in enumerate(chunks):
            results.append(pool.apply_async(find_closest_n_chunks, (chunk, chunk_p2v[idx], 100)))
        for result in results:
            step = time.time()
            print("step: {0}".format(step-start))
            result.wait()
    end = time.time()
    print(end - start)
这在启动多个不同的进程时效果很好,但是,它们在我的4核(8带多线程)CPU上不能并行工作。输出证实了这一点:

starting
step: 0.1266627311706543
starting a chunk
finished chunk
step: 15.884509086608887
starting a chunk
finished chunk
step: 24.54252290725708
starting a chunk
finished chunk
step: 33.269429445266724
starting a chunk
finished chunk
step: 42.065810680389404
消息“starting a chunk”仅在“finished a chunk”之后调用,每个chunk大约需要8-9秒,这意味着每个chunk只有在另一个chunk完成后才会启动

注意,我已经尝试复制p2v对象,以确保任务之间没有共享对象(正如预期的那样,因为它是只读的,所以没有任何更改)

你能指出我在尝试将它并行化时犯的任何错误吗

编辑:在代码顶部添加了导入,以及加载我的向量和ID的pickle语句

Edit2:我用一个伪方法替换了find_nexist_n_chunk():

def dummy():
    print("start dummy")
    time.sleep(5)
    print("end dummy")
这给了我正确的输出,在第一个进程完成之前,所有进程都将启动。然后,我在实际的find_closest方法中直接在起始打印行之后添加了time.sleep(20)。这表明存在一些并行化:

starting
step: 0.07980728149414062
starting a chunk
starting a chunk
starting a chunk
starting a chunk
finished chunk
step: 35.71958327293396
starting a chunk
finished chunk
step: 45.673808574676514
finished chunk
starting a chunk
finished chunk
step: 55.73376154899597
step: 55.73949694633484
starting a chunk
finished chunk
step: 64.74968791007996
starting a chunk
finished chunk
step: 73.77850985527039
finished chunk
step: 82.86862134933472
finished chunk
91.36373448371887

但每一个“开始一个区块”的出现都需要5-10秒。因此它们不会同时启动

您也可以显示导入语句吗?我运行了您的代码的简化版本,它确实并行运行。感谢您的帮助。我添加了导入和pickle语句来加载向量和ids。现在,我已经在多台不同的计算机(一台Linux)上尝试了该代码,但它不起作用。这很奇怪,因为您的代码似乎在我的计算机上起作用,但我当然没有您的数据结构。这有点牵强,但您是否可以创建一个没有任何数据结构的测试程序。只需要一个worker,它执行sleep(3)并返回一个整数,并且您的with mp.Pool()结构与您的相同,但也没有数据结构。这将允许我们查看是否存在阻碍并行执行的因素,或者这与您的数据/数据量有关,并且如果您将结果作为结果:with结构外部的循环-这意味着在您开始访问结果之前池将关闭,是否会发生任何变化?由于代码看起来很好,这些都是在黑暗中拍摄的。您能同时显示导入语句吗?我运行了您的代码的简化版本,它确实并行运行。感谢您的帮助。我添加了导入和pickle语句来加载向量和ids。现在,我已经在多台不同的计算机(一台Linux)上尝试了该代码,但它不起作用。这很奇怪,因为您的代码似乎在我的计算机上起作用,但我当然没有您的数据结构。这有点牵强,但您是否可以创建一个没有任何数据结构的测试程序。只需要一个worker,它执行sleep(3)并返回一个整数,并且您的with mp.Pool()结构与您的相同,但也没有数据结构。这将允许我们查看是否存在阻碍并行执行的因素,或者这与您的数据/数据量有关,并且如果您将结果作为结果:with结构外部的循环-这意味着在您开始访问结果之前池将关闭,是否会发生任何变化?这些只是在黑暗中拍摄的,因为您的代码看起来很好。