Python 在从多处理收集结果时确保正确的顺序

Python 在从多处理收集结果时确保正确的顺序,python,python-2.7,dictionary,multiprocessing,Python,Python 2.7,Dictionary,Multiprocessing,我有一个多处理脚本,它在字典上循环,如下所示: jobs = [] for key, val in datadict.items(): jobs.append(pool.apply_async(worker, (val)) pool.close() pool.join() result = dict([job.get() for job in jobs]) jobs是一个结果对象列表(其中调用get()将给出一个数据列表) 我想格式化结果,使其成为一个与输入字典具有相同键和顺序的字

我有一个多处理脚本,它在字典上循环,如下所示:

jobs = []
for key, val in datadict.items():
    jobs.append(pool.apply_async(worker, (val))

pool.close()
pool.join()
result = dict([job.get() for job in jobs])
jobs
是一个结果对象列表(其中调用
get()
将给出一个数据列表)

我想格式化结果,使其成为一个与输入字典具有相同键和顺序的字典

我想在所有工作完成后简单地这样做:

result = {key: jobs[key].get() for key, val in datadict} 
这是因为
datadict
中的键是整数(因此可用于索引作业列表)。 但是,我突然想到,可能生成的作业列表的顺序不一定与创建的顺序相同——这是真的吗?(我预计订单可能会变得混乱,因为一个流程可能比另一个流程完成得更快等)

因此,我决定将
datadict
传递到worker函数中,并将结果作为元组再次返回。因此,调用
jobs[index].get()
将返回一个元组,其中第一个值是键(刚刚通过函数),第二个值是实际结果

然后我可以创建一个字典,如下所示:

jobs = []
for key, val in datadict.items():
    jobs.append(pool.apply_async(worker, (val))

pool.close()
pool.join()
result = dict([job.get() for job in jobs])
最后的剧本是:

def worker(val, key):        
    res = "Do something to val"
    return (key, res)

if __name__ == "__main__":
    jobs = []
    for key, val in datadict.items():
        jobs.append(pool.apply_async(worker, (val, key))

    pool.close()
    pool.join()

    result = dict([job.get() for job in jobs])
但这是最好的方法吗?有两点让我感到困扰:

  • 到目前为止,
    作业
    列表的结果顺序与输入顺序匹配
  • 通过函数“传递”一个值似乎有点愚蠢(即不使用它)

  • datadict
    字典键进行显式排序,并进行迭代

    import multiprocessing
    
    def worker(val):
        res = "Do something to val {}".format(val)
        return res
    
    if __name__ == "__main__":
        datadict = {1: 'val1', 2: 'val2', 0: 'val0'}
        jobs = []
        pool = multiprocessing.Pool()
        for key in sorted(datadict): # <------------
            jobs.append(pool.apply_async(worker, (datadict[key],)))
        pool.close()
        pool.join()
        result = [job.get() for job in jobs]
        print(result)
        # ['Do something to val 0', 'Do something to val 1', 'Do something to val 2']
    

    作业可能会按顺序完成,但这不会改变
    作业
    列表的顺序。但是,您可以通过循环
    datadict.items()
    来填充
    作业
    ;这就把它们按任意顺序排列,因为字典不维持顺序

    将钥匙放入
    作业中
    将是实现您所需的一种方法:

    jobs = []
    for key, val in datadict.items():
        jobs.append((key, pool.apply_async(worker, (val,)))
    
    pool.close()
    pool.join()
    
    result = {key: job.get() for key, job in jobs} 
    

    dict
    容器不保证任何特定的订购。如果要使事情保持有序,您需要将结果存储在
    列表中

    result = [job.get() for job in jobs]
    
    或者,您可以使用维护插入顺序的:

    result = OrderedDict([job.key, job.get() for job in jobs])
    
    第二种解决方案需要一种从作业中获取密钥的方法

    更新:

    如果顺序是按键给出的,那么您可以按此属性对结果进行排序(作业需要知道其键):

    或者,如果您需要一个
    命令

    results = [job.get() for job in jobs]
    results = OrderedDict([job.key, job for job in sorted(results, key=attrgetter('key'))])
    

    这是怎么回事?假设我的字典中有两个项目,如果第二个项目首先完成,它是否会在第一个项目之前附加到作业列表中(因此位于错误的位置)?您将结果对象附加到
    jobs
    for循环中的您自己。之后没有任何东西会重新排列它们。对结果对象调用
    get
    ,等待实际结果到达,但不会更改列表的顺序。。。也许“秩序”这个词用错了。我需要将正确的结果分配给正确的键。