个人博客页面链接:http://www.shihao.online/(django搭建的个人博客,还在完善中)
linux下使用fork()创建子进程
Linux 操作系统提供了一个 fork() 函数用来创建子进程,这个函数很特殊,调用一次,返回两次,因为操作系统是将当前的进程(父进程)复制了一份(子进程),然后分别在父进程和子进程内返回。子进程永远返回0,而父进程返回子进程的 PID(大于0)。我们可以通过判断返回值是不是 0 来判断当前是在父进程还是子进程中执行。
在 Python 中同样提供了 fork() 函数,此函数位于 os 模块下。
例子:
import os
import time
ret = os.fork() #创建了一个子进程
if ret == 0: #子进程
while True:
print("-------1--------")
time.sleep(1)
else: #父进程
while True:
print("-------2--------")
time.sleep(1)
输出结果为:
-------2--------
-------1--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
无限循环。。。。。。(注:子进程和父进程的执行顺序不确定,即1和2输出顺序不一定,由操作系统的调度算法确定)
注意:如果父进程结束,子进程也跟着结束
如程序:
import os
import time
ret = os.fork()
if ret == 0:
while True:
print("---1-----")
time.sleep(1)
else:
print("---2-----")
输出结果为:
---2-----
---1-----
使用Process创建子进程
linux下可以使用fork创建子进程,但windows下不支持fork函数,但可以使用Process创建子进程
注意:与fork不同的是,主进程会等待Process子进程完成后结束。
Process语法结构如下:
Process([group [, target [, name [, args [, kwargs]]]]])
target:表示这个进程实例所调用对象;
args:表示调用对象的位置参数元组;
kwargs:表示调用对象的关键字参数字典;
name:为当前进程实例的别名;
group:大多数情况下用不到;
Process类常用方法:
is_alive():判断进程实例是否还在执行;
join([timeout]):是否等待进程实例执行结束,或等待多少秒;
start():启动进程实例(创建子进程);
run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法;
terminate():不管任务是否完成,立即终止;
Process类常用属性:
name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;
pid:当前进程实例的PID值;
from multiprocessing import Process
import time
import random
def test():
for i in range(1,5):
print("---%d---"%i)
time.sleep(1)
p = Process(target=test)
p.start() #让这个进程开始执行test函数里面的代码
p.join() #等进程p结束之后,才会继续向下走
print("---main----")
输出结果为:
---1---
---2---
---3---
---4---
---main----
进程池创建子进程
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行.
multiprocessing.Pool常用函数解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
apply(func[, args[, kwds]]):使用阻塞方式调用func
close():关闭Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;
程序(非阻塞方式):
from multiprocessing import Pool
import os
import time
def worker(num):
for i in range(2):
print("===pid=%d===num=%d"%(os.getpid(), num))
time.sleep(1)
pool = Pool(3) #定义一个进程池,最大进程数3
for i in range(5):
print("---%d---"%i)
pool.apply_async(worker, [i,]) #使用非阻塞方式调用func(并行执行,堵塞方式必须
#等待上一个进程退出才能执行下一个进程)
print("---start----")
pool.close() #关闭进程池,关闭后pool不能再添加新的请求
pool.join() #等待pool中所有子进程执行完成,必须放在close语句之后
print("---end----")
输出:
---0--- ---1--- ---2--- ---3--- ---4--- ---start---- ===pid=24958===num=0 ===pid=24959===num=1 ===pid=24960===num=2 ===pid=24958===num=0 ===pid=24960===num=2 ===pid=24959===num=1 ===pid=24960===num=3 ===pid=24958===num=4 ===pid=24960===num=3 ===pid=24958===num=4 ---end----
程序(阻塞方式):
from multiprocessing import Pool
import os
import time
def worker(num):
for i in range(2):
print("===pid=%d===num=%d"%(os.getpid(), num))
time.sleep(1)
pool = Pool(3) #定义一个进程池,最大进程数3
for i in range(5):
print("---%d---"%i)
pool.apply(worker, [i,]) #使用非阻塞方式调用func(并行执行,堵塞方式必须
#等待上一个进程退出才能执行下一个进程)
print("---start----")
pool.close() #关闭进程池,关闭后pool不能再添加新的请求
pool.join() #等待pool中所有子进程执行完成,必须放在close语句之后
print("---end----")
输出:
---0--- ===pid=24999===num=0 ===pid=24999===num=0 ---1--- ===pid=25000===num=1 ===pid=25000===num=1 ---2--- ===pid=25001===num=2 ===pid=25001===num=2 ---3--- ===pid=24999===num=3 ===pid=24999===num=3 ---4--- ===pid=25000===num=4 ===pid=25000===num=4 ---start---- ---end----
注意:进程池和fork()一样,不会等待子程序结束
例子:
from multiprocessing import Pool
import os
import time
def worker():
for i in range(2):
print("===pid=%d==="%os.getpid())
time.sleep(1)
pool = Pool(3) #定义一个进程池,最大进程数3
for i in range(5):
print("---%d---"%i)
pool.apply_async(worker) #使用非阻塞方式调用func(并行执行,堵塞方式必须
#等待上一个进程退出才能执行下一个进程)
输出:
---0---
---1---
---2---
---3---
---4---