今日内容:
1.进程的其他方法
2.僵尸进程和孤儿进程(了解)
3.验证进程之间是空间隔离的
4.守护进程
5.进程锁 重点(又叫同步锁,互斥锁)
6.进程队列(重点) Queue
7.生产者消费者模型
8.管道,进程的数据共享,信号量,事件(了解)
1.进程的其他方法
进程的ID import os
查看子进程的ID os.getpid()
查看子进程的父进程的id os.getppid()
进程名字,
p1=process(target=f1,)
print(p1.name)
查看进程是否活着,
p1.is_alive() # 查看进程是否还活着
发送结束进程的信号
p1.terminate() # 给操作系统发送一个结束进程的信号
2.僵尸进程和孤儿进程(了解)
僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
僵尸进程是有害的
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
孤儿进程是无害的.
3.验证进程之间是有空间隔离的
from multiprocessing import Process num=100 def f1(): global num num=30 print('子进程中的num',num) if __name__=='__main__': p=Process(target=f1,) p.start() p.join() print('主进程中的num',num)
最后的结果为, 打印的子进程的num的值为:30 打印的主进程中的num的值为:100,因此我们可以判断出进程之间是存在空间隔离的.
4.守护进程
守护进程: 将f1 设置为守护进程后,如果主进程结束后,f1的进程不管运行到什么地方,都是直接结束的.
import time from multiprocessing import Process def f1(): time.sleep(1) print('我是f1') def f2(): time.sleep(2) print('我是f2') if __name__=='__main__': p1=Process(target=f1,) p2=Process(target=f2,) p1.daemon=True# 此处为设置守护进程,设置守护进程必须在执行start之间设置,
守护进程的意思是如果我主进程的代码运行结束,那么你这个守护进程不管运行到什么地方,都要直接结束 p1.start() p2.start() p2.join()# 等待p2执行完毕后在运行主进程 print('主进程结束')
开启一个不同的子进程来验证一下守护进程的结束只和主进程的代码运行结束有关系,而整个程序的结束需要主进程和普通的子进程的代码都运行结束才结束.
5.进程锁,又叫互斥锁,同步锁(重点)
语法:
from multiprocessing import Process,Lock
1)
def f1(loc):
loc.acquire() # 上锁,保证程序运行到这里只能有一个进程进入里面执行
要锁的内容......
loc.release() # 解锁 ,程序代码运行完毕,开锁后,剩下的程序才能能继续抢这把锁
if __name__=='__main__':
loc=Lock() # 创建进程锁
p=Process(target=f1,args=(loc,))
2)
def f1(loc):
wIth loc:
要锁的内容......
if __name__=='__main__':
loc=Lock() # 创建进程锁
p=Process(target=f1,args=(loc,))
# 互斥锁/进程锁/同步锁 # import json import time from multiprocessing import Process,Lock def show_t(i): with open('ticket','r',encoding='utf-8') as f: ticket_data = f.read() # print(ticket_data) t_data = eval(ticket_data) # print(t_data,type(t_data)) print('%s查询剩余票数为%s'%(i,t_data['count'])) def get_t(i,l1): l1.acquire() with open('ticket', 'r', encoding='utf-8') as f: ticket_data = f.read() # print(ticket_data) t_data = eval(ticket_data) # print(t_data,type(t_data)) # print('%s查询剩余票数为%s' % (i, t_data['count'])) 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()
6.进程队列(重点) Queue
from multiprocessing import Process
q=Queue(5) # 这个队列只能放5个进程
q.put() # 往进程队列中放数据,如果进程满了会等待
q.get()# 从进程队列中拿数据
q.qsize()# 查看进程中数据的个数
q.empty() # 查看进程是否是空的
q.full() # 查看进程是否是满的
q.get_nowait()# 不等待,但是报错 一般 用try 尝试使用
q.put_nowait()# 不等待,但是报错 一般 用try 尝试使用
7.生产者消费者模型
import time from multiprocessing import Process,Queue # 生产者 def producer(q): for i in range(): time.sleep(1) s=f'大包子{i}号' print('新鲜出炉的'+s) #消费者 def consumer(q): while 1: time.sleep(2) baozi=q.get() print(baozi+'被吃了') if __name__=='__main__': q=Queue(10) pro_obj=Process(target=producer,args=(q,)) con_obj=Process(target=consumer,args=(q,)) pro_obj.start() con_obj.start()
精简SVIP版生产者消费者模型
import time from multiprocessing import Process,Queue,JoinableQueue def producer(q): for i in range(10): time.sleep(1) s=f'大包子{i}号' print('新鲜出炉的'+s) q.put(s) q.join()# 等着task_done()信号的数量,和我put进去的数量相同时,才继续执行 print('所有的包子都生产完毕了') def consumer(q): while 1: time.sleep(2) baozi=q.get() print(baozi+'被吃了') q.task_done() # 给队列发送一个去处的这个任务已经处理完毕的信号 if __name__=='__main__': q=JoinableQueue(30) # 和Queue一样都是创建一个长度为30的队列 pro_obj=Process(target=producer,args=(q,)) con_obj=Process(target=consumer,args=(q,)) pro_obj.start() con_obj.start() pro_obj.join()# 等生产者把包子全部生产完之后在结束 print('主程序结束')
什么是阻塞IO模型
IO模型就是当程序遇到阻塞的时候,程序会阻塞在这个地方不继续向下执行,直到阻塞执行完成之后,才向下执行
#实例代码:
import socket
ser=socket.socket()
ser.bind(('127.0.0.1',8000))
ser.listen()
while True:
#建立连接的时候会发生IO阻塞,如果没有建立连接,会一直阻塞在这里
conn.addr = ser.accept()
#接收和发送消息的时候也会发生IO阻塞,在数据量大的时候才能感觉出来
data = conn.recv(1024)
conn.send(xxx)
conn.close()
什么是非阻塞IO模型(不推荐使用)
当程序遇到阻塞后,立即切换到下一步去执行下一步的代码,期间不会产生阻塞和时间等待
#实例代码:
import socket
ser=socket.socket()
ser.bind(('127.0.0.1',8000))
ser.listen()
#将下面的代码都变成了非阻塞IO模型,如果遇到IO阻塞后会出现BlockingIOError,在这里如果检测到这个错误,就是已经设置了IO非阻塞模型
ser.setblocking(False)
clist=[]
wlist=[]
while True:
try:
#检测IO阻塞的错误
conn.addr = ser.accept()
#如果捕获到IO阻塞异常之后,就不会添加到这个列表中
clist.append(conn)
except BlockingIOError:
del_clist = []
#这个for循环做的事是专门收消息
for conn in clist:
try:
data = conn.recv(1024)
#如果没有拿到数据,就把它删除掉
if not data:
del_clist.append(conn)
continue
conn.send(发送的数据)
wlist.append((conn,发送的数据))
except BlockingIOError:
continue
except Exception:
conn.close()
del_clist.append(conn)
#专门发消息
del_wlist=[]
for msg in wlist:
try:
conn=msg[0]
data=msg[1]
conn.send(data)
del_wlist.append(msg)
except BlockingIOError:
pass
#将发送成功之后的那个元组从之前的列表中删除
for dd in del_wlist:
w_list.remove(dd)
#将发送完成之后关闭的套接字删除掉
for d in del_clist:
c_list.remove(d)