前面章节中,已经详解介绍了 2 种创建进程的方法,即分别使用 os.fork() 和 Process 类来创建进程。其中: 使用 os.fork() 函数创建的子进程,会从创建位置处开始,执行后续所有的程序,主
- 使用 os.fork() 函数创建的子进程,会从创建位置处开始,执行后续所有的程序,主进程如何执行,则子进程就如何执行;
-
而使用 Process 类创建的进程,则仅会执行
if "__name__"="__main__"
之外的可执行代码以及该类构造方法中 target 参数指定的函数(使用 Process 子类创建的进程,只能执行重写的 run() 方法)。
实际上,Python 创建的子进程执行的内容,和启动该进程的方式有关。而根据不同的平台,启动进程的方式大致可分为以下 3 种:
- spawn:使用此方式启动的进程,只会执行和 target 参数或者 run() 方法相关的代码。Windows 平台只能使用此方法,事实上该平台默认使用的也是该启动方式。相比其他两种方式,此方式启动进程的效率最低。
- fork:使用此方式启动的进程,基本等同于主进程(即主进程拥有的资源,该子进程全都有)。因此,该子进程会从创建位置起,和主进程一样执行程序中的代码。注意,此启动方式仅适用于 UNIX 平台,os.fork() 创建的进程就是采用此方式启动的。
- forserver:使用此方式,程序将会启动一个服务器进程。即当程序每次请求启动新进程时,父进程都会连接到该服务器进程,请求由服务器进程来创建新进程。通过这种方式启动的进程不需要从父进程继承资源。注意,此启动方式只在 UNIX 平台上有效。
在了解以上 3 种进程启动方式的基础上,我们还需要知道手动设置进程启动方式的方法,大致有以下 2 种。总的来说,使用类 UNIX 平台,启动进程的方式有以上 3 种,而使用 Windows 平台,只能选用 spawn 方式(默认即可)。
1) Python multiprocessing 模块提供了一个
set_start_method()
函数,该函数可用于设置启动进程的方式。需要注意的是,该函数的调用位置,必须位于所有与多进程有关的代码之前。例如,下面代码演示了如何显式设置进程的启动方式:
import multiprocessing import os print("当前进程ID:",os.getpid()) # 定义一个函数,准备作为新进程的 target 参数 def action(name,*add): print(name) for arc in add: print("%s --当前进程%d" % (arc,os.getpid())) if __name__=='__main__': #定义为进程方法传入的参数 my_tuple = ("http://c.biancheng.net/python/",\ "http://c.biancheng.net/shell/",\ "http://c.biancheng.net/java/") #设置进程启动方式 multiprocessing.set_start_method('spawn') #创建子进程,执行 action() 函数 my_process = multiprocessing.Process(target = action, args = ("my_process进程",*my_tuple)) #启动子进程 my_process.start()程序执行结果为:
当前进程ID: 24500
当前进程ID: 17300
my_process进程
http://c.biancheng.net/python/ --当前进程17300
http://c.biancheng.net/shell/ --当前进程17300
http://c.biancheng.net/java/ --当前进程17300
2) 除此之外,还可以使用 multiprocessing 模块提供的 get_context() 函数来设置进程启动的方法,调用该函数时可传入 "spawn"、"fork"、"forkserver" 作为参数,用来指定进程启动的方式。
需要注意的一点是,前面在创建进程是,使用的 multiprocessing.Process() 这种形式,而在使用 get_context() 函数设置启动进程方式时,需用该函数的返回值,代替 multiprocessing 模块调用 Process()。
例如,下面程序演示了如何使用 get_context() 函数设置进程启动:
import multiprocessing import os print("当前进程ID:",os.getpid()) # 定义一个函数,准备作为新进程的 target 参数 def action(name,*add): print(name) for arc in add: print("%s --当前进程%d" % (arc,os.getpid())) if __name__=='__main__': #定义为进程方法传入的参数 my_tuple = ("http://c.biancheng.net/python/",\ "http://c.biancheng.net/shell/",\ "http://c.biancheng.net/java/") #设置使用 fork 方式启动进程 ctx = multiprocessing.get_context('spawn') #用 ctx 代替 multiprocessing 模块创建子进程,执行 action() 函数 my_process = ctx.Process(target = action, args = ("my_process进程",*my_tuple)) #启动子进程 my_process.start()程序执行结果为:
当前进程ID: 18632
当前进程ID: 16700
my_process进程
http://c.biancheng.net/python/ --当前进程16700
http://c.biancheng.net/shell/ --当前进程16700
http://c.biancheng.net/java/ --当前进程16700
以上仅演示了在 Windows 平台上设置进程启动方式的效果,有兴趣的读者可自行尝试选择类 UNIX 平台测试其他启动进程的方式。