multiporcessing与apply_async

 

  官方文档中使用multiprocessing.Pool的例子如下:

from multiprocessing import Pool

def f(x):
    print(x*x)
    return x*x

def test():
    with Pool(processes=4) as pool:           # start 4 worker processes
        for i in range(6):
          result = pool.apply_async(f, (10,)) # evaluate "f(10)" asynchronously in a single process  ——参考博客
          print(result.get(timeout=1))

print(' output ')                    # 每执行一次apply_async,都会执行这一句
if __name__ == '__main__':
    test()

# 100
# 100    

  子进程相当于主进程的克隆体,会将除 __main__ 外的内容都执行一遍,即 所有函数外的内容 + 指定进程函数 都会执行,如上。

 

  有几个注意点:

1)子进程和主进程(主函数)的变量是不共享的(多线程的可以共享);子进程会将主进程的全局变量copy一份,但子进程中对全局变量的修改不影响其它进程,所以全局变量最好是只读的那种,否则也没法一起修改。——参考so

可以通过Manager实现变量共享(参考博客),但这个也无法绕过下面问题(3)。

* py3.8以上的版本有multiprocessing.shared_memory类,可以指定共享内存,适用于大块数据的处理  ——文档

2)若在执行多线程功能前使用了pickle,则子进程很可能会无法执行,出现错误:Pool not running  或 _io.BufferReadError 等问题

3)子进程在OS看来是一个文件,根据SO该文件的描述子不能超过ulimit(1024),描述子包括函数参数部分,所以子进程函数的参数不能太大,否则子进程无法执行,出现错误:...OSError: [Errno 24] Too many open files ...(子进程数太多也会出现这个问题)

 

  apply_async的特点是:执行后立即返回,而不等待结果。也就是说,若目标函数不能立即执行完,则该子进程可能执行到一半就阻塞了,没有返回的结果。

  若和get()一起使用就必定能得到结果,但就没有并行的效果了。加了callback可以完成执行得到结果,并由并行效果。——参考博客

 

  关于apply_async不执行的问题,99%是子进程出现问题

  对于子进程不报错的情况,根据博客的解释,报错需要用error_callback来承接,否则不会显式报错(用了error_callback也不一定能将所有错误都承接,python语言本身有一些特性的错误,不在它的处理范围内)。

 

** 对于子进程无法执行立即得到结果的情况,要注意不用 with,因为 with代码块结束了,会导致pool也异常结束。

# 1. stuck after with
with multiprocessing.Pool(processes=32) as pool:
    pool.apply_async()
    ...

pool.close()    # pool does not exist after "with" finished
pool.join()
# 2. ok pool = multiprocessing.Pool(processes=32) pool.apply_async() pool.close() pool.join()

 

posted @ 2022-06-10 17:42  谷小雨  阅读(781)  评论(0编辑  收藏  举报