在Unix/Linux操作系统下,提供了一个fork()系统函数,它非常特殊
- 普通函数调用,调用一次返回一次,但是fork()函数,调用一次,返回两次,因为操作系统自动把当前进程(称为父进程),复制了一份(称为子进程),然后分别在父进程和子进程内返回。
- 子进程永远返回0,而父进程返回子进程的ID
- 一个父进程可以fork出多个子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID
- 父进程、子进程执行的顺序没有规律,完全取决于操作系统的调度算法
- 各个进程有独立的运行空间,不共享全局变量
- 有时会因父进程提前退出,子进程的父进程和开始的不一致
import os
pid = os.fork()
if pid < 0:
print("fork()调用失败")
elif pid == 0:
print("子进程%s,父进程%s"(os.getpid(), os.getppid()))
#子进程在系统的pid不为0
else:
print("父进程%s,子进程%s"(os.getpid(), pid))
#父进程返回子进程的ID
输出:
我是父进程1653,我的子进程1654
我是子进程1654,我的父进程1653
multiprocessing模块是跨平台版本的多进程模块,模块提供了一个Process类来代表一个进程。
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建的进程比fork()还简单。
- Process([group[,target[,name[,args[,kargs]]]]])
- target:表示这个进程实例所调用的对象
- args:表示调用这个对象的位置和参数元组
- kwargs:表示调用对象的关键字参数字典
- group:多数情况用不到
- start():启动进程
- join():此方法等待子进程结束后再继续往下进行,通常用于进程同步
Process类常用方法
- is_alive():判断进程是否还在执行
- join([timeout]):是否等待进程实例执行结束,或等待多少秒
- run():如果没给定target参数,这个对象调用start()方法时,执行对象中的run()方法,可以重写
- terminate():不管任务是否完成,立即终止
Process类常用属性
- name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数
- pid:当前进程实例的pid值
#coding = utf-8
from multiprocessing import Process
import os
import time
def run_proc(name):
time.sleep(3)
print("子进程运行中,name=%s,pid=%s,父进程=%s"%(name,os.getppid(),os.getppid()))
if __name__ == '__main__':
print("父进程是%s"%os.getpid())
p = Process(target=run_proc,args=('test',))
print("子进程即将运行")
p.start()#启动进程
p.join()#阻塞当前进程,直到调用join方法的那个进程执行完,再继续执行当前进程
print("子进程已结束")
#
from multiprocessing import Process
import os
import time
class MyProcess(Process):
def __init__(self,interval):
super().__init__()
self.interval = interval
def run(self):
print("子进程")
startTime = time.time()
time.sleep(self.interval)
stopTime = time.time()
print("子进程id:%s,父进程id:%s,共执行多少秒%s"%(os.getppid(),os.getppid(),stopTime-startTime))
if __name__ == "__main__":#不加程序会出问题
print("主进程")
startTime = time.time()
p = MyProcess(2)
p.start()
p.join()
stopTime = time.time()
print("子进程结束,花费了%s秒"%(stopTime-startTime))
当需要创建的子进程数量不多时,可以利用multiprocessing的Process动态生成多个进程,单数如果是成百上千个,可以使用multiprocessing模块提供的Pool方法
初始化进程时,可以指定有个最大进程数,当池中的进程数达到最大值时,该请求就会等待,直到池中有进程结束,才会创建新的进程来执行。
from multiprocessing import Pool
import os
import time
import random
#进程类
def worker(msg):
t_start = time.time()
print("%s开始执行,执行进程id为%s,父进程id为%s"%(msg,os.getpid(),os.getppid()))
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执行完毕,耗时%s秒"%(t_stop-t_start))
if __name__ == "__main__":
print("++开始++")
t0 = time.time()
pool = Pool(3)
for i in range(0, 10):
pool.apply_async(worker, (i,))
pool.close()#关闭进程池,关闭后不再接受新请求
pool.join()#必须放在close语句后面
t1 = time.time()
print("++结束总耗时%s++" %(t1-t0))
进程中的消息队列Queue
from multiprocessing import Pool,Manager
import time,os,random
def write(q):
for i in "ABC":
print("正在往消息队列写入%s"%i)
q.put(i)
time.sleep(random.random())
def reader(q):
while True:
if not q.empty():
i = q.get()
print("从消息队列中读出%s"%i)
time.sleep(random.random())
else:
break
if __name__ == "__main__":
q = Manager().Queue()
pool = Pool(3)
pool.apply(write, (q,))
pool.apply(reader, (q,))