一、解释什么是进程
任务管理器:里面都是进程
对于操作系统而言,一个任务就是一个进程
进程是系统中程序执行和资源分配的基本单位,每个进程都有自己的数据段,代码段和堆栈段。
数据段:存储数据
代码段:存储代码
堆:存储对象
栈:存储普通变量
两个特点:全局变量在多个进程之间不能共享
多个进程在并行的时候,不会出现数据混乱
进程的目的:实现多任务,提高我们的执行效率
进程: 就是创建一个任务,让它去执行其他的功能
二、单任务现象
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from time import sleep 5 6 7 def run(): 8 while True: 9 print("sunck is a nice man") 10 sleep(1.2) 11 12 13 if __name__ == '__main__': 14 while True: 15 print("sunck is a good man") 16 sleep(1) 17 18 19 # 不会执行 run 方法,只有上面的while循环结束才可以执行 20 # 要让这两个任务同时执行,就是多任务 21 run()
三、启动进程实现多任务
multiprocessing 库
multiple: adj.数量多的;多种多样的;
n.倍数;
processing: v.处理;加工;
n.过程;加工处理;处置;进行;
adj.经过特殊加工的;(用化学方法等)处理过的;
在linux下可以使用C语言的方法fork实现多进程,但是它不支持window,
但是这个三方库multiprocessing库是一个跨平台版本的多进程模块
提供了一个Process类来代表一个进程对象
所以我们要使用多进程就要引入multiprocessing库
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import os 5 from time import sleep 6 7 from multiprocessing import Process 8 9 10 # 子进程需要执行的代码 11 def run(adj): 12 # os.getpid() 获取当前进程ID号 13 # os.getppid() 获取当前进程的父进程ID号 14 while True: 15 print("sunck is a %s man--%s--%s"%(adj, os.getpid(),os.getppid())) 16 sleep(1.2) 17 18 19 if __name__ == '__main__': 20 print("主(父)进程启动") 21 # os.getpid() 获取当前父进程ID号 22 print(os.getpid()) 23 24 # 创建一个子进程(在父进程下创建一个进程,故称为该进程的子进程) 25 p = Process(target=run, args=("nice",)) 26 # target:说明 该子进程要执行的任务、代码、函数 27 # args:可以给target的函数传参数,是一个元组类型,单个参数要加逗号, 28 29 # 启动进程 30 p.start() 31 32 while True: 33 print("sunck is a good man") 34 sleep(1)
四、父子进程的先后顺序
使用join(),让父进程等待子进程执行完毕,再执行。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from multiprocessing import Process 5 from time import sleep 6 7 def run(args): 8 print("子进程启动") 9 sleep(3) 10 print("子进程结束") 11 12 if __name__ == '__main__': 13 print("主(父)进程启动") 14 15 p = Process(target=run, args=("nice",)) 16 p.start() 17 18 # 父进程的结束不能影响子进程,让父进程等待子进程,再执行父进程 19 p.join() 20 21 print("父进程结束")
五、全局变量在多个子进程之间不能共享
因为每个进程都会有自己独立的数据段,代码段,和堆栈段。
每次创建新的进程的时候,该进程就会将全局变量做一个属于自己的备份。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from multiprocessing import Process 5 from time import sleep 6 7 NUM = 100 8 9 10 def run(): 11 print("子进程开始") 12 global NUM 13 NUM += 1 14 print(NUM) 15 print("子进程结束") 16 17 18 if __name__ == '__main__': 19 print("父进程开始") 20 21 p = Process(target=run) 22 p.start() 23 p.join() 24 25 print(NUM) 26 # 在子进程中修改全局变量对父进程中的全局变量没有影响 27 # 为什么没影响呢?因为他在创建子进程时,对全局变量做了一个备份,父进程中的与子进程中的 28 # NUM是两个完全不同的变量 29 print("父进程结束--%d" % NUM)
六、启动大量子进程(进程池)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import os 5 import time 6 import random 7 8 # from multiprocessing import Process 9 # 为了对多个进程好管理,使用进程池 10 from multiprocessing import Pool 11 12 13 def run(name): 14 print('子进程%s启动--%s' % (name, os.getpid())) 15 strat = time.time() 16 time.sleep(random.choice([1, 2, 3])) 17 end = time.time() 18 print('子进程%s结束--%s--耗时%.2f' % (name, os.getpid(), end-strat)) 19 20 21 if __name__ == '__main__': 22 print('父进程启动') 23 24 # 创建多个进程 25 # 进程池 26 # 4:表示可以同时执行的进程数量 27 # 参数可以写,也可以不写,不写pool默认大小是CPU核心数 28 pp = Pool(4) 29 30 # 创建进程,创建的进程数要大于CPU核心数,这样才能体验到多进程的效果 31 # 这里因为进程都是干一样的活,所以使用for循环创建进程 32 # 子进程的执行顺序是没有顺序的。 33 for i in range(5): 34 # 创建进程,放进进程池,统一管理 35 pp.apply_async(run, args=(i,)) 36 37 ''' 38 如果每个进程干的活不一样,那就单独创建每一个进程,不要写for循环。 39 例: 40 pp.apply_async(func1, agrs=()) 41 pp.apply_async(func2, agrs=()) 42 pp.apply_async(func3, agrs=()) 43 pp.apply_async(func4, agrs=()) 44 pp.apply_async(func5, agrs=()) 45 ''' 46 47 # 在调用join之前,必须先调用close,并且在调用close之后,就不能再继续添加新的进程了 48 pp.close() 49 # 进程池对象调用的join,会等待进程池中的所有的子进程结束完毕,再去执行父进程。 50 pp.join() 51 52 print("父进程结束") 53 54 ''' 55 运行结果: 这里进程看似0,1,2,3启动的,实际上,进程启动是没有顺序的。 56 父进程启动 57 子进程0启动--5251 58 子进程1启动--5252 59 子进程2启动--5253 60 子进程3启动--5254 61 子进程2结束--5253--耗时1.00 62 子进程0结束--5251--耗时1.00 63 子进程4启动--5253 64 子进程3结束--5254--耗时1.00 65 子进程1结束--5252--耗时2.00 66 子进程4结束--5253--耗时3.00 67 父进程结束 68 '''
七、二次封装
继承第三方的某各类,然后重写它的 init 方法,run 方法
1 #二次封装的文件名,一般是:自己的名字+第三方库的名称 2 3 import os 4 import time 5 from multiprocessing import Process 6 7 8 class SunckProcess(Process): 9 def __init__(self, name): 10 super().__init__() 11 self.name = name 12 13 def run(self): 14 super().run() 15 print('子进程(%s-%s)启动' % (self.name, os.getpid())) 16 # 子进程的功能 17 time.sleep(3) 18 print('子进程(%s-%s)结束' % (self.name, os.getpid()))
1 from sunckProcess import SunckProcess 2 3 4 if __name__ == '__main__': 5 print('父进程启动') 6 7 # 创建子进程 8 p = SunckProcess('test') 9 # 在这里不要调用进程里面的run方法,调用它的start就会自动调用进程对象的run方法 10 p.start() 11 p.join() 12 13 print("父进程结束")
八、进程间通信
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import os 5 import time 6 from multiprocessing import Process 7 from multiprocessing import Queue 8 9 10 def write(args): 11 print('启动写子进程%s' % (os.getpid())) 12 for letter in ['a', 'b', 'c', 'd']: 13 q.put(letter) 14 time.sleep(1) 15 print('结束写子进程%s' % (os.getpid())) 16 17 18 def read(args): 19 print('启动读子进程%s' % (os.getpid())) 20 while True: 21 value = q.get(True) 22 print('value = ' + value) 23 print('结束读子进程%s' % (os.getpid())) 24 25 26 if __name__ == '__main__': 27 # 父进程创建队列,并传递给子进程 28 q = Queue() 29 pw = Process(target=write, args=(q,)) 30 pr = Process(target=read, args=(q,)) 31 32 pw.start() 33 pr.start() 34 # 35 pw.join() 36 # pr进程里面是个死循环,无法等待其结束,只能强行结束 37 pr.terminate() 38 39 print('父进程结束')