每日测验
昨日内容回顾
- 死锁现象
```python “”” 即便你知道如何抢锁释放锁 也极有可能造成程序的死锁现象 
后续我们在写项目的时候 也不会自己去处理锁的问题 都是底层封装好的 所以你不用担心 “””
- 递归锁```python"""它也是一把互斥锁,但是它可以被第一个抢到它的人连续的acquire和release每acquire一次内部有一个引用计数加1每release一次内部有一个引用计数减1只要引用计数不为0 永远也无法被其他人抢到"""
信号量
"""信号量在不同的领域和知识阶段可能对应不同的概念如果将互斥锁比喻成一个厕所 那么信号量就相当于多个厕所"""
event事件
```python “”” 一些线程/进程等待另外一些线程/进程发送可以运行的信号 才开始运行 from threading import Event e = Event()
等待
e.wait()
发送信号
e.set() “””
- 各种队列```python"""1 常见队列 queue先进先出q = queue.Queue()q.put()q.get(timeout=3)q.get_nowait()q.full()q.empty()2 后进先出 LifoQueue()q = queue.LifoQueue()q.put()q.get()3 优先级 PriorityQueue()q = queue.PriorityQueue()q.put((10,'data'))q.put((-5,'data'))元祖里面的第一个参数是数字 并且支持负数数字越小优先级越高"""
- 进程池线程池
```python “”” 硬件的发展肯定是赶不上软件的开发速度的 
思考我们以前借助于开设进程和线程的方式来实现TCP服务端的并发 每来一个客户端就开设一个进程或者线程
无论是开设进程还是开设线程其实都需要消耗一定的资源
我们应该在保证计算机硬件安全的情况下,最大限度的利用计算机
池的概念 它的出现是为了保证计算机硬件的安全 降低了程序的运行效率 但是保证了计算机硬件安全 “””
进程池线程池都不需要我们自己去造 直接使用封装好的模块
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
1 生成进程池线程池
pool1 = ThreadPoolExecutor() # 不填默认是cpu个数的五倍 pool2 = ProcessPoolExecutor() # 不填默认就是cpu的个数
2 朝池子中提交任务
pool1.submit(task,args…) # 异步提交
3 submit其实会返回一个Future类的对象 该对象调用result就能获取到任务的结果
res = pool1.submit(task,args…) res.result() # 同步
4 池子对象的方法
pool1.shotdown() # 关闭池子 等待池子中所有的任务运行结束 再继续往后执行代码
5 异步回调机制
“””给每一个异步提交的任务绑定一个方法,一旦任务有结果了会立刻自动触发该方法””” pool1.submit(task,args).add_done_callback(call_back)
注意异步回调函数拿到的也是一个对象
- 协程```python"""单线程下实现并发这个概念完全是我们程序员自己想出来多道技术切换+保存状态我们想通过代码层面自己检测IO行为。一旦遇到IO代码层面实现切换这样给操作系统的感觉好像我这个程序一直运行没有IO欺骗操作系统从而最大化的利用CPU一味的切换加保存状态也有可能会降低程序的效率计算密集型的 不行IO密集型的 可以"""
- gevent模块
```python该模块能够帮我们检测IO并实现切换
from gevent import monkey;monkey.patch_all() from gevent import spawn 
spawn在检测的时候 是异步提交的
spawn(server).join() g = spawn(server) g.join
- 基于协程实现TCP服务端单线程下的并发```python# 代码稍微搂一眼 感受它的牛逼之处
总结
"""多进程下面开设多线程多线程下面再利用协程最大长度的提升软件运行的效率"""
今日内容概要
IO模型简介
"""我们这里研究的IO模型都是针对网络IO的Stevens在文章中一共比较了五种IO Model:* blocking IO 阻塞IO* nonblocking IO 非阻塞IO* IO multiplexing IO多路复用* signal driven IO 信号驱动IO* asynchronous IO 异步IO由signal driven IO(信号驱动IO)在实际中并不常用,所以主要介绍其余四种IO Model。"""#1)等待数据准备 (Waiting for the data to be ready)#2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)同步异步阻塞非阻塞常见的网络阻塞状态:acceptrecvrecvfromsend虽然它也有io行为 但是不在我们的考虑范围
阻塞IO模型

"""我们之前写的都是阻塞IO模型 协程除外"""import socketserver = socket.socket()server.bind(('127.0.0.1',8080))server.listen(5)while True:conn, addr = server.accept()while True:try:data = conn.recv(1024)if len(data) == 0:breakprint(data)conn.send(data.upper())except ConnectionResetError as e:breakconn.close()# 在服务端开设多进程或者多线程 进程池线程池 其实还是没有解决IO问题该等的地方还是得等 没有规避只不过多个人等待的彼此互不干扰
非阻塞IO

"""要自己实现一个非阻塞IO模型"""import socketimport timeserver = socket.socket()server.bind(('127.0.0.1', 8081))server.listen(5)server.setblocking(False)# 将所有的网络阻塞变为非阻塞r_list = []del_list = []while True:try:conn, addr = server.accept()r_list.append(conn)except BlockingIOError:# time.sleep(0.1)# print('列表的长度:',len(r_list))# print('做其他事')for conn in r_list:try:data = conn.recv(1024) # 没有消息 报错if len(data) == 0: # 客户端断开链接conn.close() # 关闭conn# 将无用的conn从r_list删除del_list.append(conn)continueconn.send(data.upper())except BlockingIOError:continueexcept ConnectionResetError:conn.close()del_list.append(conn)# 挥手无用的链接for conn in del_list:r_list.remove(conn)del_list.clear()# 客户端import socketclient = socket.socket()client.connect(('127.0.0.1',8081))while True:client.send(b'hello world')data = client.recv(1024)print(data)
总结
"""虽然非阻塞IO给你的感觉非常的牛逼但是该模型会 长时间占用着CPU并且不干活 让CPU不停的空转我们实际应用中也不会考虑使用非阻塞IO模型任何的技术点都有它存在的意义实际应用或者是思想借鉴"""
IO多路复用
"""当监管的对象只有一个的时候 其实IO多路复用连阻塞IO都比比不上!!!但是IO多路复用可以一次性监管很多个对象server = socket.socket()conn,addr = server.accept()监管机制是操作系统本身就有的 如果你想要用该监管机制(select)需要你导入对应的select模块"""import socketimport selectserver = socket.socket()server.bind(('127.0.0.1',8080))server.listen(5)server.setblocking(False)read_list = [server]while True:r_list, w_list, x_list = select.select(read_list, [], [])"""帮你监管一旦有人来了 立刻给你返回对应的监管对象"""# print(res) # ([<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080)>], [], [])# print(server)# print(r_list)for i in r_list: #"""针对不同的对象做不同的处理"""if i is server:conn, addr = i.accept()# 也应该添加到监管的队列中read_list.append(conn)else:res = i.recv(1024)if len(res) == 0:i.close()# 将无效的监管对象 移除read_list.remove(i)continueprint(res)i.send(b'heiheiheiheihei')# 客户端import socketclient = socket.socket()client.connect(('127.0.0.1',8080))while True:client.send(b'hello world')data = client.recv(1024)print(data)
总结
"""监管机制其实有很多select机制 windows linux都有poll机制 只在linux有 poll和select都可以监管多个对象 但是poll监管的数量更多上述select和poll机制其实都不是很完美 当监管的对象特别多的时候可能会出现 极其大的延时响应epoll机制 只在linux有它给每一个监管对象都绑定一个回调机制一旦有响应 回调机制立刻发起提醒针对不同的操作系统还需要考虑不同检测机制 书写代码太多繁琐有一个人能够根据你跑的平台的不同自动帮你选择对应的监管机制selectors模块"""
异步IO
"""异步IO模型是所有模型中效率最高的 也是使用最广泛的相关的模块和框架模块:asyncio模块异步框架:sanic tronado twisted速度快!!!"""import threadingimport asyncio@asyncio.coroutinedef hello():print('hello world %s'%threading.current_thread())yield from asyncio.sleep(1) # 换成真正的IO操作print('hello world %s' % threading.current_thread())loop = asyncio.get_event_loop()tasks = [hello(),hello()]loop.run_until_complete(asyncio.wait(tasks))loop.close()
四个IO模型对比
参考博客园图解,稍微了解即可
网络并发知识点梳理
- 软件开发架构
 互联网协议
"""osi七层五层每一层都是干嘛的以太网协议 广播风暴IP协议TCP/UDP"""
三次握手四次挥手
- socket简介
 - TCP黏包问题 定制固定长度的报头
 - UDP协议
 - socketserver模块
 - 操作系统发展史
 - 多道技术
 - 进程理论
 - 开启进程的两种方式
 - 互斥锁
 - 生产者消费者模型
 - 线程理论
 - 开启线程的两种方式
 - GIL全局解释器锁
 - 进程池线程池
 - 协程的概念
 - IO模型的了解
 
