Python 多处理池.apply\u async占用内存

Python 多处理池.apply\u async占用内存,python,python-3.x,parallel-processing,multiprocessing,python-multiprocessing,distributed-system,Python,Python 3.x,Parallel Processing,Multiprocessing,Python Multiprocessing,Distributed System,用例: exec_log = multiprocessing.Manager().list([0, '']) lock = multiprocessing.Manager().Lock() cores = multiprocessing.cpu_count() pool = multiprocessing.Pool(processes=cores) # Parameters a to j for a in a_list: # a_list contains 2 elements for

用例:

exec_log = multiprocessing.Manager().list([0, ''])
lock = multiprocessing.Manager().Lock()
cores = multiprocessing.cpu_count()
pool = multiprocessing.Pool(processes=cores)

# Parameters a to j
for a in a_list: # a_list contains 2 elements
    for b in b_list: # b_list contains 2 elements
        for c in c_list: # c_list contains 5 elements
            for d in d_list: # d_list contains 10 elements
                for e in e_list: # e_list contains 10 elements
                    for f in f_list: # f_list contains 5 elements
                        for g in g_list: # g_list contains 20 elements
                            for h in h_list: # h_list contains 10 elements
                                for i in i_list: # i_list contains 10 elements
                                    for j in j_list: # j_list contains 10 elements
                                        pool.apply_async(prestart, (df, start_date, end_date, curr_date, 
                                                                    analysis_period, a, b, c, d, e,
                                                                    f, g, h, i, j, exec_log, lock))
pool.close()
pool.join()
logger.info(exec_log[1])
  • 将使用10台服务器(16核128GB RAM)处理20亿个参数组合
  • 每个服务器使用pool.apply_async()(Python版本3.7)处理2亿个组合
  • 使总处理时间尽可能短
  • 问题:

    exec_log = multiprocessing.Manager().list([0, ''])
    lock = multiprocessing.Manager().Lock()
    cores = multiprocessing.cpu_count()
    pool = multiprocessing.Pool(processes=cores)
    
    # Parameters a to j
    for a in a_list: # a_list contains 2 elements
        for b in b_list: # b_list contains 2 elements
            for c in c_list: # c_list contains 5 elements
                for d in d_list: # d_list contains 10 elements
                    for e in e_list: # e_list contains 10 elements
                        for f in f_list: # f_list contains 5 elements
                            for g in g_list: # g_list contains 20 elements
                                for h in h_list: # h_list contains 10 elements
                                    for i in i_list: # i_list contains 10 elements
                                        for j in j_list: # j_list contains 10 elements
                                            pool.apply_async(prestart, (df, start_date, end_date, curr_date, 
                                                                        analysis_period, a, b, c, d, e,
                                                                        f, g, h, i, j, exec_log, lock))
    pool.close()
    pool.join()
    logger.info(exec_log[1])
    
  • Python耗尽所有内存并抛出错误“RuntimeError:无法启动新线程”和“OSError:[Errno 12]无法分配内存”
  • 我正在考虑将.apply\u async()方法替换为.apply(),但我想如果将非阻塞模式更改为阻塞模式,将对总处理时间产生严重影响

    是否有人可以帮助找到此场景的最佳解决方案(占用的时间最少)

    我的代码:

    exec_log = multiprocessing.Manager().list([0, ''])
    lock = multiprocessing.Manager().Lock()
    cores = multiprocessing.cpu_count()
    pool = multiprocessing.Pool(processes=cores)
    
    # Parameters a to j
    for a in a_list: # a_list contains 2 elements
        for b in b_list: # b_list contains 2 elements
            for c in c_list: # c_list contains 5 elements
                for d in d_list: # d_list contains 10 elements
                    for e in e_list: # e_list contains 10 elements
                        for f in f_list: # f_list contains 5 elements
                            for g in g_list: # g_list contains 20 elements
                                for h in h_list: # h_list contains 10 elements
                                    for i in i_list: # i_list contains 10 elements
                                        for j in j_list: # j_list contains 10 elements
                                            pool.apply_async(prestart, (df, start_date, end_date, curr_date, 
                                                                        analysis_period, a, b, c, d, e,
                                                                        f, g, h, i, j, exec_log, lock))
    pool.close()
    pool.join()
    logger.info(exec_log[1])
    
    Q:有人能帮找到这个场景的最佳解决方案吗(花费的时间最少)

    当然,让我们检查一下购物清单的可见部分:

    1)
    避免
    Lock()
    -处理
    ,如果任何形式的
    Lock()
    -ing仍然存在,您希望代码执行的并行组织会一个接一个地重新编排成阻塞状态(让所有其他人等待轮到他们——不管你在steriods服务器上投入多少大内存——所有人都在等待轮到他们,大部分时间都试图“抓住”锁())

    2)
    避免使用任何形式的共享,如果任何形式的共享资源仍然存在,您希望并行工作流(再次)求助于等待片刻,等待任何此类共享资源从任何其他人的使用中释放出来,并可能开始被此流程使用

    3)
    避免任何过多的进程/内存实例化(除了您已经经历过的RAM上限崩溃之外,这些对于HPC级并行问题解决方案来说也是非常昂贵的,包括:

    • [TIME]
      -域…实例化加载项开销…~大量的
      [ns]
    • [SPACE]
      -域…新的内存分配需求由O/S以显著的附加成本以不断增长的规模处理,远远超过了~数千个
      [ns]
      ,最糟糕的是陷入虚拟内存交换窒息…再次支付相关的
      [TIME]
      -移动数据内存块的域成本(在RAM副本中,NUMA CPU核心非本地RAM目的地的成本约为300-350[ns])加上基于数据量的I/O带宽驱动和空闲RAM通道可用性进一步限制了此类数据传输延迟。在陷入交换的情况下,O/S协调(即,超出您的控制范围)交换流的成本约为1000 x~10000 x更糟…并通过在该时间段内具有最高优先级阻止任何其他尝试计算和读取/写入RAM,因此,没有人希望在计算期间发生这些情况的另一个原因)
    使用
    多处理。get\u all\u start\u methods()
    将显示本地主机O/S可以提供的所有选项,以消除(小规模缓解)不必要的过量RAM分配

    使用
    len(os.sched\u getaffinity(0))
    控件而不是上面使用的
    多处理.cpu\u count()
    ,将消除本地主机过度订阅免费使用的cpu内核数量(也减少了“just”
    [并发]
    -如果O/S关联映射策略限制用户程序使用所有指定的硬件核心平台,则必须等待调度程序命令的RAM拷贝,然后才能执行RAM/CPU


    基于
    的“外部”迭代器的“糟糕的”
    可能总会得到改进,但核心策略更为重要:

    可能会将代码重构为计算模式: 一个干净且注重性能的计算方法可以平衡现实世界的成本与人们在花费这些成本后将享受的净性能收益

    许多“记住语法”的方法无法扩展到一些不断增长的主要方法之上-首先,经历了从缓存计算中驱逐到感受RAM的实际成本的罪恶(这在教科书示例和演示中没有观察到)接下来是内存数据流的成本,对于越来越大的数据量,最后但并非最不重要的是,来自多处理的天真期望的成本(这取决于O/S和版本,可能会带来分配许多完整python会话副本的生成附加成本,这可能会导致内存错误崩溃,就像上面所述的情况一样)

    考虑到10台服务器各有16个内核和128 GB RAM,很有希望的移入概念将在使用数据计算
    prestart()
    时测试python进程的大小,然后在一台服务器中产生的“工作线程”不会超过它们全部装入RAM(以避免交换)接下来,使用任何高性能、低延迟的工具(如ZeroMQ或nanomsg are),创建一个消息传递/信令元层,以协调在这个分布式工作池中的许多作业的智能参数传递,并设计工作流,使您永远不会将一条数据传递两次(由于系统和O/S属性的原因,参数传递的附加成本比O(n)更高),因此在性能驱动的系统中,绝对不要移动数据两次


    遵循这些简单的规则并不便宜,但没有更快的方法(免费的越少…)