获取进程id和名字[getpid()--is_terminate()]--结束进程和判断运行[is_alive()--is_alive]--守护线程[daemon()]--进程锁[Lock()]--队列[Queue()--JoinableQueue()]--数据共享[Manager]
一、如何获取进程的id号和进程的名字.
os.getpid() #获取本进程的id号
os.getppid() #获取本进程的父进程的id号
import os from multiprocessing import Process def f1(): print('f1进程的pid',os.getpid()) print('f1进程的父进程的pid',os.getppid()) if __name__ == '__main__': p1 = Process(target=f1,name='欢迎') p1.start() print(p1.name) print('p1进程的pid',p1.pid) print('本进程的id',os.getpid()) # p1.pid #返回结果为p1进程的id号 # os.getpid()#返回本进程的id号 # os.getppid()#返回为本进程的父进程id号 # p1.name()#返回p1进程的名字
二、如何手动结束子进程,以及判断子进程是否还在运行
obj.is_terminate() #给操作系统发送结束进程的信号
obj.is_alive() #判断进程是否在运行,返回值True,False
import time from multiprocessing import Process def f1(): print('子进程1号') if __name__ == '__main__': p = Process(target=f1,) p.start() print(p.is_alive()) #判断子进程是否还活着,是否还在运行 p.terminate() #给操作系统发送一个结束进程的信号 time.sleep(0.5) #需要延迟一会再判断是否还存活,因为系统结束进程需要处理很多东西 print(p.is_alive())
三、如何验证进程存在空间隔离
对于打印结果的解释:首先程序自上往下走,先打印一遍100,开启子进程后,系统copy一份代码走,并运行,又打印一遍100,子进程修改的只是自己进程里的全局变量,
而父进程的变量还是那个,这就验证了进程之间存在空间隔离.
from multiprocessing import Process num = 100 def f1(): global num num = 3 #修改全局变量的值 print('f1进程中的num',num) print('>>>>>',num) if __name__ == '__main__': p = Process(target=f1,) p.start() p.join() print('主进程中的num',num) 打印结果为: >>>>> 100 >>>>> 100 f1进程中的num 3 主进程中的num 100
四、关于守护进程
obj(进程的实例化对象).daemon = True #开启守护进程,一定要在开启进程( obj.start() )前设置 什么是守护进程: 1.在主进程代码执行结束后就终止(应用场景:子进程需要跟父进程一起结束时) 2.守护进程内无法开启子进程,否则抛异常
from multiprocessing import Process def f1(): print("xxx") def f2(): print("p普通子进车") if __name__ == '__main__': p = Process(target = f1,) p.daemon = True #开启守护进程,一定要在开启该进程(p.start())前设置,父进程代码执行结束,这个守护进程也结束. p.start() #p.join() #给主进程阻塞,守护进程有机会执行里面的代码 print("主进程结束.") p2 = Process(target = f2,) #普通进程不受限制 p2.start()
五、关于僵尸进程和孤儿进程概念
僵尸进程:在子进程执行完,而主进程还没有执行完的时候,系统会保留执行的子进程一些信息(id号,名字...),它会随着主进程的结束而被清理掉
孤儿进程:主进程在子进程前结束了,这个时候该子进程的一些信息没人管了,就叫孤儿进程,最后会被系统清理.
六、关于互斥锁\进程锁\同步锁:
什么时进程所\互斥锁\同步锁: 控制进程在共享一个文件,或同一个打印终端的时候,产生竞争时的错乱.原理是把并发改成串行 with obj(锁的实例化对象): #简易写法 需要上锁的代码 Lock.acquire() #加锁 Lock.release() #解锁
from multiprocessing import Process,Lock import time def show_t(i): with open("ticket","r",encoding = "utf-8")as f: #用with open打开文件,前2个可以用位置参数,但第三个必须用关键字传参 ticket_data = f.read() t_data = eval(ticket_data) print("%s查询剩余票数为%s"%(i,t_data["count"])) def get_t(i,l1): # l1.acquire()#加锁 with l1: #用了该枷锁方法,就不用手动解锁了 with open("ticket","r",encoding="utf-8")as f: ticket_data = f.read() #ticket票 data数据 t_data = eval(ticket_data) if t_data["count"]>0: t_data["count"]-=1 print("%s抢票成功"%i) time.sleep(0.2) with open("ticket","w")as f: f.write(str(t_data)) else: print("没有票了") # l1.release() #解锁 if __name__ == '__main__': l1 = Lock() for i in range(10): p1 = Process(target=show_t,args=(i,)) p1.start() for i in range(10): p2=Process(target=get_t,args=(i,l1)) #传两个参数要加括号 p2.start()
七、关于multiprocessing包的Queue模块的使用
方法介绍: obj.put() #往队列里面放数据,如果队列里面满了,会阻塞 obj.put_nowait() #满了就报错(不会阻塞程序,可以通过捕获异常来进行其他的操作) obj.get() #从队列里面取数据,如果队列里面空了,会阻塞(等待) obj.get_nowait() #空了就报错(不会阻塞程序,可以通过捕获异常来进行其他的操作) obj.full() #查看队列是否满了,满了返回True,但该命令的执行速度比put和get的速度快,所以结果不准确 obj.empty() #查看队列是否空了,空了返回True,结果同理,有时不准确 obj.qsize() #返回当前队列内容的长度,结果也不准确
举例:关于Queue
from multiprocessing import Process,Queue def f1(q): q.put('约吗?') if __name__ == '__main__': q = Queue(3) p = Process(target=f1,args=(q,)) p.start() #开启子进程 son_p_msg = q.get() #从队列里面拿数据,队列为空,则阻塞等待 print('来自子进程的消息:',son_p_msg)
八、JoinableQueue方法(跟Queue相近)
JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
方法介绍:
q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
下面例子中,应用此方法目的,是为了解决,当有多个消费者程序,去队列里拿数据的时候,不知道队列里是否空了,而此方法,会往队列里面放入一个信号,表示该数据被拿走了.
q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
import time from multiprocessing import Process,Queue,JoinableQueue #生产者 def producer(q): for i in range(10): time.sleep(0.2) s = '大包子%s号'%i print(s+'新鲜出炉,拿去用') q.put(s) q.join() #等待的是队列的内容处理完毕(q是队列的实例化对象),而不是等待上面代码执行,就等着task_done()信号的数量,和我put进去的数量相同时,才继续执行下面代码
print('所有的任务都被处理了,继续潜行吧骚年们')
#消费者 def consumer(q): while 1: time.sleep(0.5) baozi = q.get() print(baozi+'被吃了') q.task_done() #给队列发送一个取出的这个任务已经处理完毕的信号 if __name__ == '__main__': # q = Queue(30) q = JoinableQueue(30) #同样是一个长度为30的队列 pro_p = Process(target=producer,args=(q,)) con_p = Process(target=consumer,args=(q,)) pro_p.start() con_p.daemon = True #开启守护进程,消费者会随着主进程的结束而终结 con_p.start() pro_p.join() #让主进程等待(生产者)子进程 print('主进程结束')
九、Manager方法
什么是Manager方法:
Manager是是一种数据共享的方法.一种较为高级的多进程通信方式
进程之间的通信:队列、管道、数据共享(Manager).
队列,管道,这些方式只适用于多个进程都是源于同一个父进程的情况。如果多个进程不是源于同一个父进程,只能用共享内存,信号量等方式,还有就是数据共享(Manager)
多进程共同去处理共享数据的时候,就和我们多进程同时去操作一个文件中的数据是一样的,不加锁就会出现错误的结果,进程不安全的,所以也需要加锁
import time from multiprocessing import Process,Manager,Lock #创建进程的方法\数据共享的方法\互斥锁方法 def f1(m_d,l2): with l2: tmp = m_d["num"] tmp -= 1 time.sleep(0.1) m_d["num"]=tmp if __name__ == '__main__': m = Manager() #实例化数据共享的对象 l2 = Lock #实例化锁的对象 m_d = m.dict({"num":100}) p_list = [] for i in range(10): p = Process(target=f1,args=(m_d,l2)) p.start() p_list.append(p) [pp.join() for pp in p_list] print(m_d["num"])