Python 之 进程与进程池的创建和使用
进程:计算机中已运行的程序,一个进程在运行的过程中可能存在的状态
- 新生(new):进程新产生中。
- 运行(running):正在运行。
- 等待(waiting):等待某事发生,例如等待用户输入完成。亦称“阻塞”(blocked),也就是进行了输入/输出 I/O的操作,这时CPU就会记录当前的执行状态,去执行下一个处于就绪的进程
- 就绪(ready):排班中,等待CPU。
- 结束(terminated):完成运行。
各状态名称可能随不同操作系统而相异;对于单CPU系统(UP),任何时间可能有多个进程为等待、就绪,但必定仅有一个进程在运行。
CPU按照一定的调用的规则对处于就绪进程进行调用执行
常用的调度规则:1.依序循环调用(将CPU处理的时间分成固定的时间片,对进程进行处理)
2.最短先做排班法, 对于短作业或短进程进行优先的处理
3.先进先出,先来先执行
并发:一个CPU轮询去执行多个任务,某一时刻只能有一个任务在执行,但由于CPU的执行速度比较快,让人感觉是多个任务同时执行(单核CPU)
并行:多个CPU在执行多个任务,某一时刻有多个任务在执行(多核CPU,并行的同时,存在并发)
并发运行:让计算机同时运行多个程序或者是同时运行一个程序多个进程或线程
注意的是:进程没有任何的共享状态,进程修改的数据,改动仅限于该进程内部
# 创建子进程的两种方法: # Process 类的介绍 class Process(object): def __init__(self, group=None, target=None, name=None, args=(), kwargs={}): #target表示的是调用对象,即子进程要执行的任务 self.name = ''#子进程的名称,每创建一个子进程就命名为Process-1 self.daemon = False#代表的是p为后台运行的守护进程,如果p的父进程终止的时候,p也会随之终止,并且设置为true后,p不能创建子进程,需在p.start之前设置 self.authkey = None self.exitcode = None self.ident = 0 self.pid = 0 #子进程的进程ID self.sentinel = None def run(self):#进程启动的时候自动执行的方法, 由p.run方法去调用target 指定的函数,这是自定义类的时候一定要重写的方法 pass def start(self):#启动进程,并调用子进程中的p.run方法 pass def terminate(self):#强制终止进程p,但没有执行任何的清理的操作, 如果p创建了子进程的话, 那么该子进程就成了僵尸进程 #如果p还保存了一个锁,那么这个锁也不会被释放,进而导致死锁 pass def join(self, timeout=None):#主线程等待p终止,强调的(主线程处于等的状态,而p处于运行的 状态) pass def is_alive(self):#判断子进程p是否还在运行 return False # 方案1 import time from multiprocessing import Process def func1(n,m): print(n) print(m) time.sleep(0.01) print('我是1') def func2(): time.sleep(0.01) print('我是2') if __name__ == '__main__': p1 = Process(target=func1,args = 10)#args >>>用于传参 p1 = Process(target=func1,kwargs ={'n':10,'m':20})#kwargs >>>用于关键字传参 p2 = Process(target=func2)#target是要由该run()方法调用的可调用对象。它默认为None(Process 类中的run的方法默认是pass) p1.start() p2.start() print('主进程在这等待') p1.join()#主进程等待P1结束后再进行主进程下面的代码,原因是在对象p1在执行完上面的 上面的定义的代码之后才会执行后面的join 方法, # 所以执行join方法之后,因为在Process 类中的join方法默认是pass , # time.sleep(10) print('主进程结束') # 方案2: import time from multiprocessing import Process class pro(Process): def __init__(self,n): super().__init__() self.n =n def run(self): time.sleep(2) print('3333') if __name__ == '__main__':#在网络编程中一定要使用这条命令的原因是,在创建子进程的时候,相当于将这个代码文件作为模块导入到另一个内存空间 #然后在运行,最后在调用指定的方法 p = pro(10) # p.start()# print('程序结束') 记忆:创建一个进程的实例p,p.start() 触发,告诉系统开启进程
进程池
from multiprocessing import Pool,Process import time def func(i): num = 0 for j in range(5): # print(i+j) num += i return num if __name__ == '__main__': pool = Pool(4)#设置池中可以有多少个子进程在运行,在这里直接开辟了4子进程的内存,之后始终使用这几个进程去执行所有的任务 # start_time = time.time() # gg = [] # for i in range(200): # p = Process(target=func,args = (i,)) 不使用地址池执行的异步的操作 # p.start() # gg.append(p) # [a.join() for a in gg] # end_time = time.time() # print(end_time-start_time) s_time = time.time() a = pool.map(func,range(200))#map是异步执行的,并且自带close和join print(a)#map方法与内置的map函数行为基本一致,在它会使进程阻塞与此直到结果返回 e_time = time.time() print(e_time-s_time) # map_async(func, iterable[, chunksize[, callback]]) # 与map用法一致,但是它是非阻塞的。与apply_async的套路基本一样
# # p.apply_async的异步执行的方法,和p.apply用法一致,但是它是非阻塞的且支持结果返回后进行回调。 from multiprocessing import Pool,Process import time def func(i): num = 0 # for j in range(5): while 1: num += i time.sleep(1) gg = input('') print(num) if num == 100: return num if __name__ == '__main__': pool = Pool(5) for i in range(10): # pool.apply(func,args=(i,))#同步执行的任务机制,每次创建一个子进程,主进程都会等待子进程返回结果才,进行后面的操作 ret = pool.apply_async(func,args=(i,)) #主循环在运行的过程中等待apply_async的返回结果, # 主循环运行结束后,即使子进程还没有返回,整个程序就直接结束,即使apply_async的是不阻塞的,由于apply_async的返回结果是一个结果对象 #要通过使用ret.get() 才能获取到数据,但是.get()就具有阻塞的功能,一般是将获取到的值添加的一个新的列表中,等所有子进程都结束的时候 #在通过遍历该该列表通过.get()的方法将结果提取 # 解决主循环运行结束后,即使子进程还没有返回,整个程序就直接结束的问题是: # pool.close() #锁定进程池,让一次只能执行池的大小的容量,即使有些子进程运行的速度较快, # # 运行完之后也干等,不把位置让给其他的不是同一批次进来的子进程, # pool.join()#作用是等待进程池的所有任务结束 # pool.close()#锁定pool ,使其不接受新的任务 # pool.terminate()#结束工作进程,不处理未处理的任务 # pool.join()#主进程阻塞等待子进程的退出,一般用在close和terminate之后 # # 回调函数 # from multiprocessing import Pool,Process # import os # def func(i): # print(os.getpid()) # return i*i # def gg(P): # print(os.getpid())#证明回调函数是在主函数上运行的 # print(P) # if __name__ == '__main__': # pool = Pool(4) # pool.apply_async(func,args=(3,),callback=gg)#callback函数不能直接传参,只能通过接收前一个函数的返回值 # print(os.getpid()) # pool.close() # pool.join()