Pytorch只支持spawn和forserver创建子进程方式。Windows平台下的Python,默认使用spawn,也只支持spawn模式,Unix默认使用fork模式

  • spawn:使用此方式启动的进程,只会执行和target参数或者run()方法相关的代码,父进程启动一个新的Python解释器进程,子进程只继承运行run()方法所需的资源。来自父进程的不必要的文件描述符和句柄将不会被继承。Windows 平台只能使用此方法,事实上该平台默认使用的也是该启动方式。相比其他两种方式,此方式启动进程的效率最低
  • fork:使用此方式启动的进程,基本等同于主进程(即主进程拥有的资源,该子进程全都有)。因此,该子进程会从创建位置起,和主进程一样执行程序中的代码。注意,此启动方式仅适用于 UNIX 平台,os.fork() 创建的进程就是采用此方式启动的
  • forserver:使用此方式,程序将会启动一个服务器进程。即当程序每次请求启动新进程时,父进程都会连接到该服务器进程,请求由服务器进程来创建新进程。通过这种方式启动的进程不需要从父进程继承资源。注意,此启动方式只在UNIX平台上有效

Python下使用spawn模式

cifar_main封装好的深度学习函数

  1. multiprocessing全局设置spawn模式
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import multiprocessing

multiprocessing.set_start_method("spawn")
# ctx = multiprocessing.get_context("spawn")
pool = multiprocessing.Pool(2)
res = pool.map_async(cifar_main, range(25, 200, 25))

pool.close()
pool.join()
print(res.get())
  1. multiprocessing获取spawn模式的上下文
1
2
3
4
5
6
7
8
9
import multiprocessing

ctx = multiprocessing.get_context("spawn")
pool = ctx.Pool(2)
res = pool.map_async(cifar_main, range(25, 200, 25))

pool.close()
pool.join()
print(res.get())

错误示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
multiprocessing.set_start_method("spawn")
    pool = multiprocessing.Pool(4)
auc_list = []
for mem_dim in range(25, 1500, 25):
    auc_list.append([
        mem_dim,
        pool.apply_async(cifar_main, (mem_dim, )).get()
    ])
pool.close()
pool.join()
print(auc_list)

这个代码运行起来,发现从始至终只有一个进程在运行,但堆栈里面确实有四个进程。这是代码的逻辑问题,调用get获取子进程的结果,添加到auc_list,然后主进程初始化一个子进程后,就在等待它的结果返回,最后成了单进程的代码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
multiprocessing.set_start_method("spawn")
pool = multiprocessing.Pool(4)
res_list = []
for mem_dim in range(25, 1500, 25):
    memae_app = MemAETrainer(chnum_in=3, mem_dim=mem_dim, epoch=64)
    # auc_list.append([
    #     mem_dim,
    #     .get()
    # ])
    res_list.append([
        mem_dim,
        pool.apply_async(cifar_main, (mem_dim, )).get()
])
pool.close()
pool.join()
for mem_dim, res in res_list:
    auc_list.append([mem_dim, res.get()])
print(auc_list)

这里先等所有进程完成初始化后,等待它们运行结束后,获取返回结果。同时注意运行时候,显卡占用的内存不要太满,不然获取结果的时候,会因为显存溢出报错。

参考链接

https://blog.csdn.net/kelxLZ/article/details/114591236