python中多进程编程详解

来源:互联网 发布:字符大小写转换 c语言 编辑:程序博客网 时间:2024/06/08 06:00

由于个人知识面有限,以下就说说我对python中多进程编程的理解,如果有错误的地方,请多多指教。
在python中有三种方式创建多进程:fork,process,pool

一: fork应用

import osimport timeprint("只有主进程执行此语句")#调用fork函数后,会产生2个值:子进程的pid和父进程的pid,# 其中子进程的pid为0,父进程的pid为子进程的pid,其实就相当于返回了2个子进程号#以下为os模块中fork函数的解释#1.Fork a child process.#2.Return 0 to child process and PID of child to parent process.pid = os.fork() #调用os模块的fork函数创建进程print("主进程和子进程都能执行此语句,进程id==%d"%os.getpid())if pid == 0:    #子进程执行代码块    print("我是子进程,子进程id是%d,父进程id是%d"%(os.getpid(),os.getppid()))elif pid > 0:    #父进程执行的代码块    #下句语句中的pid容易跟if判断中的pid混淆    print("我是父进程,父进程id是%d,子进程id是%d"%(os.getpid(),pid))

os.getpid() 获取当前进程id
os.getppid() 获取父进程id

注意:1: fork函数只能在unix中运行。
2: 父进程和子进程执行没有先后顺序,执行顺序由系统根据相关规则调用。
3: 主进程不会等所有子进程结束后而结束。

二: process应用
由于window无法调用fork函数,如果要在window创建多进程,则需要用到multiprocessing模块,而multiprocessing模块就是跨平台版本的多进程模块。

from multiprocessing import Processimport timedef test():    while True:        print("1-----我是子进程")        time.sleep(2)p = Process(target=test)p.start()while True:    print("2----我是主进程")    time.sleep(2)

上处代码为使用Process类创建的实例

from multiprocessing import Processimport timeimport osdef test1(interval):    start = time.time()    time.sleep(interval)    print("我是test1,我的进程号是%d,我的父进程id是%d"%(os.getpid(),os.getppid()))    end = time.time()def test2(interval):    start = time.time()    time.sleep(interval)    print("我是test2,我的进程号是%d,我的父进程id是%d"%(os.getpid(),os.getppid()))    end = time.time()p1 = Process(target=test1,args=(5,))p1.start()print("p1.pid = %d"%p1.pid)p1.join()p2 = Process(target=test2,args=(1,))p2.start()print("p2.pid = %d"%p2.pid)

上段代码中的join是指阻塞进程,当所有的对象进程都结束后其他进程才可继续向下执行程序。
此外: join函数可以加阻塞时间,如果加上时间,则表示阻塞系统指定时间,如p1.join(2),到达指定时间后,如果子进程没有结束,那么主进程可以和子进程同时执行。如果不指定阻塞时间,则表示等待对象进程执行完毕后,主进程才可继续向下运行。
注意:主进程会等待子进程的结束而结束
下面将介绍Process类中常用方法和属性
常用属性:
target:表示这个进程实例所调用对象;
args:表示调用对象的位置参数元组;
kwargs:表示调用对象的关键字参数字典;
pid:当前进程实例的PID值;
常用方法:
start() 创建进程实例同时并启动进程
is_alive():判断进程实例是否还在执行;
join([timeout]):是否等待进程实例执行结束,或等待多少秒
terminate():不管任务是否完成,立即终止
run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法,一般用于继承Process类中重写run方法

重写run方法案例如下:

from multiprocessing import Processimport timestart = time.time()class MyProcess(Process):    def __init__(self,num):        super().__init__()        self.num = num    def run(self):        start = time.time()        print("子进程开始执行")        time.sleep(self.num)        end = time.time()        print("子进程执行时间是%#.5f"%(end-start))myProcess = MyProcess(2)myProcess.start()# myProcess.run()# myProcess.join()end = time.time()print("主进程执行时间是%#.5f"%(end-start))

三: pool应用
使用场景和使用原理:
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行。
Pool分为两种:apply_async 非阻塞式和apply 阻塞式
下面将这两种使用方法和区别进行介绍
apply_async 非阻塞式,以下是案例:

from multiprocessing import Poolimport timeimport osimport randomstart = time.time()def work(num):    start = time.time()    time.sleep(random.random()*2)    end = time.time()    print("%d执行的进程id是%d,父进程id是%d,执行时间是%#.5f"%(num,os.getpid(),os.getppid(),(end-start)))pool = Pool(3)for i in range(0,10):    # pool.apply_async(work,args=(i,)) #非阻塞式    pool.apply(work, args=(i,))  #阻塞式pool.close()# pool.join()#使用非阻塞式时打开下面for循环#for j in range(0,12):#   time.sleep(random.random()*2)#   print("主进程的pid是%d,j==%d"%(os.getpid(),j))end = time.time()print("主进程的id是%d,运行时间是%d"%(os.getpid(),(end-start)))

当使用非堵塞式时,主进程和子进程同时执行,并且主进程不会等待子进程的结束而结束。
当使用堵塞式时,系统会等待一个进程结束之后在执行其他进程。这类似与单进程。

multiprocessing.Pool常用函数解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
apply(func[, args[, kwds]]):使用阻塞方式调用func
close():关闭Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;

原创粉丝点击