一.先讲一个形象比喻五种io模型

1.阻塞I/O模型

老李去火车站买票,排队三天买到一张退票。

耗费:在火车站吃喝拉撒3天,其他事一件没干。

2.非阻塞I/O模型

老李去火车站买票,隔12小时去火车站文有没有退票,三天后买到一张票。

耗费:往返车站6次,路上6小时,其他时间做了好多事。

3.I/O

1)select/poll

老李去火车站买票,委托黄牛,(select黄牛一次只能帮1024个人买票,poll黄牛无上限)然后每隔离6小时打电话黄牛询问,黄牛三天内买到票,然后老李去火车站交钱领票。

耗费:往返车站2次,路上2小时,黄牛手续费100,打电话17次

2)epoll

老李去火车站买票,委托黄牛,黄牛买到后即通知老李去领,然后老李去火车站交钱领票。

耗费:往返车站两次,路上2小时,黄牛手续费100元,无需打电话。

4)信号驱动I/O模型

老李去火车站买票,给售票员留下电话,有票后,售票员电话通知老李,然后老李去火车站交钱领票。

耗费:往返车站2次,路上2小时,免费黄牛100元,无需打电话。

5)异步I/O模型

老李去火车站买票,给售票员留下电话,有票后,售票员电话通知老李并快递送票上门。

耗费:往返车站1次,路上一小时,免黄牛费100,无需打电话。

二.waitdata 和 copydata

1)等待数据准备 (Waiting for the data to be ready)
2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)

记住这两点很重要,因为这些IO模型的区别就是在两个阶段上各有不同的情况。

补充

#1、输入操作:read、readv、recv、recvfrom、recvmsg共5个函数,如果会阻塞状态,则会经理wait data和copy data两个阶段,如果设置为非阻塞则在wait 不到data时抛出异常

#2、输出操作:write、writev、send、sendto、sendmsg共5个函数,在发送缓存区满了会阻塞在原地,如果设置为非阻塞,则会抛出异常

#3、接收外来链接:accept,与输入操作类似

#4、发起外出链接:connect,与输出操作类似

三.阻塞IO模型
#服务端
from concurrent.futures import ThreadPoolExecutor
import socket server = socket.socket()
#重用端口
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server.bind(("127.0.0.1",9999)) server.listen(5) #线程池
pool=ThreadPoolExecutor(3) def data_handler(conn):
print("一个新连接...")
while True:
data = conn.recv(1024)
conn.send(data.upper()) while True:
conn,addr = server.accept()
#切到处理数据的任务去执行
pool.submit(data_handler,conn) #客户端
import socket
c = socket.socket() c.connect(("127.0.0.1",9999)) while True:
msg = input(">>>:")
if not msg:continue
c.send(msg.encode("utf-8"))
data = c.recv(1024)
print(data.decode("utf-8"))

四.非阻塞IO模型

    在非阻塞IO中 需要不断循环询问操作是否有需要处理的数据

    这一来 对应程序而言 效率确实高

    但是操作系统而言 你的程序就像一个病毒 CPU江被你强行霸占

    当你的TCP程序 没有锁 没有数据接收 没有数据发送时 就是在做无用循环 浪费系统资源

#服务器
from concurrent.futures import ThreadPoolExecutor
import socket server = socket.socket()
#重用端口
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server.bind(("192.168.11.96",9998)) server.listen(5) #设置是否为阻塞 默认阻塞
server.setblocking(False) def data_handler(conn):
print("一个新连接..")
while True:
data = conn.recv(1024)
conn.send(data.upper())
#已经连接的客户端
clients = []
# 需要发送的数据
send_datas=[]
#已经发送完的 需要删除的数据
del_datas = []
# 待关闭的客户端
closed_cs = []
import time
while True:
try:
conn,addr = server.accept()
#切到处理数据的任务去执行
#代码走到这里才算是连接成功
#把连接成功的客户端存起来
clients.append(conn)
except BlockingIOError:
# print("没有可以处理的连接 就干别的活儿")
#要处理的是已经连接成功的客户端
# 接受数据
for c in clients:
try:
data = c.recv(1024)
if not data:
#对方关闭了连接
c.close()
#从客户端列表中删除它
closed_cs.append(c)
continue
print("收到%s"%data.decode("utf-8"))
#现在非阻塞 send直接往缓存塞 如果缓存满了 肯定有错误 需要单独处理
#c.send(data.upper())
send_datas.append((c,data))
except BlockingIOError:
pass
except ConnectionRefusedError:
# 对方关闭了连接
c.close()
#从客户端iebook中删除它
closed_cs.append(c)
#处理发送数据
for data in send_datas:
try:
data[0].send(data[1].upper())
#发送成功需要删除 不能直接删除
# send_datas.remove(data)
del_datas.append(data)
except BlockingIOError:
continue
except ConnectionRefusedError:
# 客户端连接需要删除
data[0].close()
closed_cs.append(data[0])
#等待发送的数据需要删除
del_datas.append(data)
# 删除无用数据
for d in del_datas:
# 从待发送的列表中删除
send_datas.remove(d)
del_datas.clear()
for c in closed_cs:
clients.remove(c)
closed_cs.clear() #客户端 from concurrent.futures import ThreadPoolExecutor
import socket server = socket.socket()
#重用端口
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server.bind(("192.168.11.96",9998)) server.listen(5) #设置是否为阻塞 默认阻塞
server.setblocking(False) def data_handler(conn):
print("一个新连接..")
while True:
data = conn.recv(1024)
conn.send(data.upper())
#已经连接的客户端
clients = []
# 需要发送的数据
send_datas=[]
#已经发送完的 需要删除的数据
del_datas = []
# 待关闭的客户端
closed_cs = []
import time
while True:
try:
conn,addr = server.accept()
#切到处理数据的任务去执行
#代码走到这里才算是连接成功
#把连接成功的客户端存起来
clients.append(conn)
except BlockingIOError:
# print("没有可以处理的连接 就干别的活儿")
#要处理的是已经连接成功的客户端
# 接受数据
for c in clients:
try:
data = c.recv(1024)
if not data:
#对方关闭了连接
c.close()
#从客户端列表中删除它
closed_cs.append(c)
continue
print("收到%s"%data.decode("utf-8"))
#现在非阻塞 send直接往缓存塞 如果缓存满了 肯定有错误 需要单独处理
#c.send(data.upper())
send_datas.append((c,data))
except BlockingIOError:
pass
except ConnectionRefusedError:
# 对方关闭了连接
c.close()
#从客户端iebook中删除它
closed_cs.append(c)
#处理发送数据
for data in send_datas:
try:
data[0].send(data[1].upper())
#发送成功需要删除 不能直接删除
# send_datas.remove(data)
del_datas.append(data)
except BlockingIOError:
continue
except ConnectionRefusedError:
# 客户端连接需要删除
data[0].close()
closed_cs.append(data[0])
#等待发送的数据需要删除
del_datas.append(data)
# 删除无用数据
for d in del_datas:
# 从待发送的列表中删除
send_datas.remove(d)
del_datas.clear()
for c in closed_cs:
clients.remove(c)
closed_cs.clear()

五.异步IO模型

import asyncio
asyncio.coroutine()
from concurrent.futures import ThreadPoolExecutor def task():
print("read start")
with open(r"D:\python视频存放目录\上海python全栈4期\day40\多路复用,降低CPU占用\服务器.py",encoding="utf-8") as f:
text = f.read()
# f.write()
print("read end")
return text def fin(f):
print("fin")
print(f.result()) pool = ThreadPoolExecutor(1)
future = pool.submit(task)
future.add_done_callback(fin) print("主 over")
# 这种方式看起来像是异步IO 但是对于子线程而言不是
# 在子线程中 执行read 是阻塞的 以为CPU必须切走 但是不能保证切到当前程序的其他线程
# 想要的效果就是 在执行read 是不阻塞 还能干其他活 谁能实现 只有协程
# asyncio 内部是使用的是协程

六.IO模型比较分析

第四十天 并发编程之io模型的更多相关文章

  1. python并发编程之IO模型 (四十九)

    IO模型介绍 http://www.cnblogs.com/linhaifeng/articles/7454717.html

  2. 第十篇.6、python并发编程之IO模型

    一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非 ...

  3. Python并发编程之IO模型

    目录 IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) IO多路复用 异步IO IO模型比较分析 selectors模块 一.IO模型介绍 Stevens ...

  4. python并发编程之IO模型,

    了解新知识之前需要知道的一些知识 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调 ...

  5. 并发编程之IO模型

    一.阻塞IO(blocking IO) from concurrent.futures import ThreadPoolExecutor import socket server = socket. ...

  6. Python之旅:并发编程之IO模型

    一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非 ...

  7. python全栈开发从入门到放弃之socket并发编程之IO模型

    一 IO模型介绍 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问 ...

  8. 并发编程之IO模型比较和Selectors模块

    主要内容: 一.IO模型比较分析 二.selectors模块 1️⃣ IO模型比较分析 1.前情回顾: 上一小节中,我们已经分别介绍过了IO模型的四个模块,那么我想大多数都会和我一样好奇, 阻塞IO和 ...

  9. python并发编程之IO模型(Day38)

    一.IO模型介绍 为了更好的学习IO模型,可以先看同步,异步,阻塞,非阻塞 http://www.cnblogs.com/linhaifeng/articles/7430066.html#_label ...

随机推荐

  1. Item 18: 使用srd::unique_ptr来管理独占所有权的资源

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 当你需要一个智能指针的时候,std::unique_ptr通常是最 ...

  2. Arduino通过L9110进行电机控制

    L9110S是为控制和驱动电机设计的两通道推挽式功率放大专用集成电路器件,将分立电路集成在单片IC之中,使外围器件成本降低,整机可靠性提高. 该芯片有两个TTL/CMOS兼容电平的输入,具有良好的抗干 ...

  3. C#里面滥用String造成的性能问题

    前两天给我们的json写一个解析函数, 之前用的正宗的json parser, 支持完整的json特性. 但是实际上我们用到特性, 只有key-value的映射, value的类型只有数字和字符串两种 ...

  4. flask登录插件 flask-login

    Flask-Login为Flask提供了用户会话管理,它处理了日常的登入登出且长时间记住用户的会话 使用: 1.配置,初始化 LoginManager 创建实例 loginManger = Login ...

  5. hibernate坑边闲话3

    could not initialize proxy - no Session] with root cause org.hibernate.LazyInitializationException: ...

  6. c++入门之结构体初步

    结构体实际上是一种数据结构的雏形,对结构体的灵活使用很多时候可以带来很多便利.下面给出一个关于结构体的程序: #include "iostream" # include " ...

  7. Django的模板语言

      Django模板系统 官方文档 常用语法 只需要记两种特殊符号: {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 {{ 变量名 }} 变量名由字母数字和下划线组成. ...

  8. #Leetcode# 633. Sum of Square Numbers

    https://leetcode.com/problems/sum-of-square-numbers/ Given a non-negative integer c, your task is to ...

  9. 网站之robots.txt文件

    一.robots.txt是什么?   robots.txt是一个纯文本文件,在这个文件中网站管理者可以声明该网站中不想被搜索引擎访问的部分,或者指定搜索引擎只收录指定的内容. 当一个搜索引擎(又称搜索 ...

  10. Visual Studio2012调试时无法命中断点

    今天在调试代码的时候发现在Debug模式下无法命中断点,然后一步步去检查原因,最后发现是在项目-->属性-->生成-->高级-->调试信息被设置为None,然后在选项中将其选择 ...