在Python(Windows)中使用池进行多处理

在Python(Windows)中使用池进行多处理,python,numpy,multiprocessing,pool,Python,Numpy,Multiprocessing,Pool,我必须以一种并行的方式进行研究,以使它运行得更快。我不熟悉python中的多处理库,但还不能使它成功运行。 在这里,我正在调查每一对(来源,目标)是否在我研究的不同框架之间的特定位置。有几点: 这是一个功能,我希望运行得更快(不是几个进程) 随后执行该过程;这意味着将每个帧与前一帧进行比较 此代码是原始代码的一种非常简单的形式。代码输出一个剩余值列表 我正在使用Windows操作系统 有人可以检查代码(多处理部分)并帮助我改进它以使其正常工作吗。谢谢 import numpy as np fro

我必须以一种并行的方式进行研究,以使它运行得更快。我不熟悉python中的多处理库,但还不能使它成功运行。 在这里,我正在调查每一对(来源,目标)是否在我研究的不同框架之间的特定位置。有几点:

  • 这是一个功能,我希望运行得更快(不是几个进程)
  • 随后执行该过程;这意味着将每个帧与前一帧进行比较
  • 此代码是原始代码的一种非常简单的形式。代码输出一个剩余值列表
  • 我正在使用Windows操作系统
  • 有人可以检查代码(多处理部分)并帮助我改进它以使其正常工作吗。谢谢

    import numpy as np
    from multiprocessing import Pool, freeze_support
    
    
    def Main_Residence(total_frames, origin_list, target_list):
        Previous_List = {}
        residence_list = []
    
        for frame in range(total_frames):     #Each frame
    
            Current_List = {}               #Dict of pair and their residence for frames
            for origin in range(origin_list):
    
                for target in range(target_list):
                    Pair = (origin, target)         #Eahc pair
    
                    if Pair in Current_List.keys():     #If already considered, continue
                        continue
                    else:
                        if origin == target:
                            if (Pair in Previous_List.keys()):            #If remained from the previous frame, add residence
                                print "Origin_Target remained: ", Pair
                                Current_List[Pair] = (Previous_List[Pair] + 1)
                            else:                                           #If new, add it to the current
                                Current_List[Pair] = 1
    
            for pair in Previous_List.keys():                        #Add those that exited from residence to the list
                if pair not in Current_List.keys():
                    residence_list.append(Previous_List[pair])
    
            Previous_List = Current_List
        return residence_list
    
    if __name__ == '__main__':
        pool = Pool(processes=5)
        Residence_List = pool.apply_async(Main_Residence, args=(20, 50, 50))
        print Residence_List.get(timeout=1)
        pool.close()
        pool.join()
        freeze_support()
    
    Residence_List = np.array(Residence_List) * 5
    

    在这里介绍的上下文中,多处理没有意义。 您将创建五个子流程(以及属于池的三个线程,用于管理工作人员、任务和结果),以便一次执行一个函数。所有这些都是以系统资源和执行时间为代价的,而您的四个工作进程根本不做任何事情。多处理不会加快函数的执行速度。特定示例中的代码总是比在主进程中直接执行
    Main\u Residence(20,50,50)
    慢。

    要使多处理在这样的上下文中有意义,您手头的工作需要分解为一组同质任务,这些任务可以并行处理,其结果可能稍后合并

    例如(不一定是一个好的例子),如果您想要计算一系列数字的最大素数因子,您可以将为任何特定数字计算该因子的任务委托给池中的工作人员。然后,几个工人将并行进行这些单独的计算:

    def largest_prime_factor(n):
        p = n
        i = 2
        while i * i <= n:
            if n % i:
                i += 1
            else:
                n //= i
        return p, n
    
    
    if __name__ == '__main__':
        pool = Pool(processes=3)
        start = datetime.now()
        # this delegates half a million individual tasks to the pool, i.e. 
        # largest_prime_factor(0), largest_prime_factor(1), ..., largest_prime_factor(499999)      
        pool.map(largest_prime_factor, range(500000))
        pool.close()
        pool.join()
        print "pool elapsed", datetime.now() - start
        start = datetime.now()
        # same work just in the main process
        [largest_prime_factor(i) for i in range(500000)]
        print "single elapsed", datetime.now() - start
    
    (最大素数因子
    函数取自in)

    正如您所看到的,池的执行速度大约是相同工作量的单个进程执行速度的两倍,同时在三个进程中并行运行。这是由于多处理/池引入的开销造成的

    因此,您声明示例中的代码已经简化。您必须分析原始代码,看看是否可以将其分解为同质任务,这些任务可以传递到您的池中进行处理。如果这是可能的,使用多处理可能会帮助您加快程序的速度。否则,多处理可能会花费您的时间,而不是节省时间

    编辑:
    因为你要求对代码提出建议。关于你的职能我几乎不能说什么。您自己说过,这只是一个提供MCVE的简化示例(顺便说一句,非常感谢!大多数人不会花时间将代码缩减到最低限度)。无论如何,代码审查的请求更适合于

    利用可用的任务委派方法进行一些研究。在我的主要因素示例中,使用
    apply\u async
    带来了巨大的损失。与使用
    map
    相比,执行时间增加了九倍。但我的示例只使用了一个简单的iterable,您的每个任务需要三个参数。这可能是星图的一种情况,但它仅在Python 3.3中可用。
    无论如何,任务数据的结构/性质基本上决定了要使用的正确方法。
    我对您的示例函数的多处理进行了一些q&d测试。 输入定义如下:

    inp = [(20, 50, 50)] * 5000  # that makes 5000 tasks against your Main_Residence
    
    在Python3.6中,我在三个子进程中运行了这个函数,除了删除了
    print
    station(I/O是昂贵的)之外,没有改变函数。我每次都使用、和对结果进行迭代,以解释异步结果上的阻塞
    get()

    以下是输出:

    starmap elapsed 0:01:14.506600
    apply elapsed 0:02:11.290600
    starmap async elapsed 0:01:27.718800
    apply async elapsed 0:01:12.571200
    # btw: 5k calls to Main_Residence in the main process looks as bad 
    # as using apply for delegation
    single elapsed 0:02:12.476800
    
    如您所见,虽然所有四种方法都做相同的工作量,但执行时间不同;您选择的
    apply\u async
    似乎是最快的方法

    编码风格。你的代码看起来很。。。非常规:)您使用大写的带下划线的单词作为名称(函数名和变量名),这在Python中几乎是不允许的。此外,将名称
    Previous_List
    分配给字典也是。。。有问题。请看一看,特别是本节,了解Python的常用编码风格


    print
    的外观判断,您仍然在使用Python 2。我知道,在公司或机构环境中,这有时是你所能得到的。不过,请记住,

    感谢您的解释。非常有用的指导。最初的代码当然不同,也更长,但主要部分是相似的,有三个for循环。我将按照你在第二段中的建议进行研究。欢迎对守则提出任何建议或修改。谢谢。我非常感谢你为回答我的问题所花费的时间、精力和提出的建议。非常感谢。嗨@shmee,我有一个关于在Windows笔记本电脑上运行
    多处理.Pool
    的问题。我希望你能花点时间来检查一下这个问题。非常感谢你的帮助!
    starmap elapsed 0:01:14.506600
    apply elapsed 0:02:11.290600
    starmap async elapsed 0:01:27.718800
    apply async elapsed 0:01:12.571200
    # btw: 5k calls to Main_Residence in the main process looks as bad 
    # as using apply for delegation
    single elapsed 0:02:12.476800