目录:

  IO模型
    阻塞IO
    非阻塞IO
    IO多路复用
    异步IO

总结:

1.阻塞IO模型
多线程 多进程 线程池 进程池 全是阻塞IO
2.非阻塞IO
协程是一种非阻塞IO
1.setblocking(False) 将阻塞修改为非阻塞
2.一旦是非阻塞 在执行accept recv send 就会立马尝试读写数据 一旦数据没准备好就抛异常
3.捕获异常
4.如果没有异常说明数据准备好了 直接处理
5.捕获到异常 那就做别的事情 可以实现单线程并发的效果,但会大量占用CPU资源 3.多路复用
将所有连接交给select来管理 管什么? 管哪个连接可以被处理
作为处理任务的一方事情变少了 不需要重复不断的问操作系统拿数据 而是等待select返回需要处理的连接
等待则意味着select是阻塞的 一.创建连接 和管理连接
1.创建服务器socket对象
2.将服务器对象交给select来管理
3.一旦有客户端发起连接 select将不在阻塞
4.select将返回一个可读的socket对象(第一次只有服务器)
5.服务器的可读代表有连接请求 需要执行accept 返回一个客户端连接conn 由于是非阻塞 不能立即去recv
6.把客户端socket对象也交给select来管理 将conn加入两个被检测的列表中 7.下一次检测到可读的socket 可能是服务器 也可能客户端 所以加上判断 服务器就accept 客户端就recv
8.如果检测到有可写(可以send就是系统缓存可用)的socket对象 则说明可以向客户端发送数据了
7 和 8 执行顺序不是固定的 二.处理数据收发
两个需要捕获异常的地方
1.recv 执行第7步 表示可以读 为什么异常 只有一种可能客户端断开连接
还需要加上if not 判断是否有数据 ;linux下 对方下线不会抛出异常 会收到空消息
2.send 执行第8步 表示可以写 为什么异常 只有一种可能客户端断开连接 4.异步IO
   不仅仅指网络IO,也包括本地IO
非阻塞IO 和 多路复用 解决都是网络IO的阻塞问题
本地IO 可以通过子线程 或子进程 来避免阻塞 但是对子线程或子进程而言 依然会阻塞 最终的解决方案就是协程 asyncio 该模快实现异步IO 内部使用协程实现 

IO模型:

网络IO:明显阻塞发生在服务端的accept和recv,IO主要是在wait data 和copy data
recv/accept:
wait data:等待客户端产生数据——》客户端OS--》网络--》服务端操作系统缓存
copy data:由本地操作系统缓存中的数据拷贝到应用程序的内存中
send:
copy data 图 例:

阻塞IO:

线程池实现阻塞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:

通过setblocking(False)设置非阻塞:
  程序会一直循环向操作系统要数据,造成无效占用
  1、对cpu的无效占用率过高
  2、不能即时反馈客户端的信息
服务端:
 from socket import *
import time
server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
# 设置阻塞为False
server.setblocking(False)
conn_l=[]#连接的客户端
while True:
try:#客户端异常断开
print('总连接数[%s]' % len(conn_l))
conn,addr=server.accept()#是在向操作系统发请求,要连接
conn_l.append(conn)#连接上添加到列表
except BlockingIOError:
del_l=[]#存储断开连接的客户端
for conn in conn_l:
try:#收不到数据
data=conn.recv(1024)
if len(data) == 0:
# 如果没收到数据,删除连接
del_l.append(conn)
continue
conn.send(data.upper())
except BlockingIOError:
pass
except ConnectionResetError:
del_l.append(conn)
#循环删除异常的客户端
for conn in del_l:
conn_l.remove(conn)
客户端:
 from socket import *
import os client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080)) while True:
msg='%s say hello' %os.getpid()
client.send(msg.encode('utf-8'))
data=client.recv(1024)
print(data.decode('utf-8'))

IO多路复用:

服务端:
 from concurrent.futures import ThreadPoolExecutor
import socket
import select
# select 帮你从一堆连接中找出来需要被处理的连接 server = socket.socket()
# 重用端口
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server.bind(("192.168.11.210",9999)) server.listen(5) # 设置是否为阻塞 默认阻塞
server.setblocking(False) def data_handler(conn):
print("一个新连接..")
while True:
data = conn.recv(1024)
conn.send(data.upper()) # 需要检测的 是否可读取的列表 (recv就是一个读取操作)
rlist = [server,]
# 需要检测的 是否写入的列表 (send就是写入操作)
wlist = [] # 需要发送的数据 目前是因为 我们要把接收的数据在发回去 所以搞了这个东西 正常没有这种需求
# 目前客户端与服务器端 交互 是必须客户端发送数据 服务器端才能返回数据 正常没有这种需求
dic = {} while True: # 用于检测需要处理的连接 需要不断检测 所以循环
# rl目前可读的客户端列表 wl目前可写的客户端列表
rl,wl,xl = select.select(rlist,wlist,[]) # select默认阻塞 阻塞到任意一个连接可以被处理
print(len(rl))
# 处理可读的socket
for c in rl:
# 无论是客户端还是服务器只要可读就会执行到这里
if c == server:
# 接收客户端的连接请求 (一个读操作)
conn,addr = c.accept()
# 将新连接也交给select来检测
rlist.append(conn)
else:# 不是服务器 就是客户端 客户端可读 可以执行recv
try:
data = c.recv(1024)
if not data:
c.close()
rlist.remove(c)
print("%s 发送 %s" % (c,data.decode("utf-8")))
# 给客户端发送数据 前要保证目前可以发送 将客户端加入检测列表
wlist.append(c) # 正常开发中 不可能必须客户端发送数据过来后 才能 给客户端发送
# 所以这个添加到检测列表的操作 应该建立连接后立即执行
# 要发送的数据
dic[c] = data
except ConnectionResetError:
# 客户端关闭连接
c.close()
rlist.remove(c)
# 处理可写的socket
for c in wl:
print(c)
try:
c.send(dic[c].upper())
# 删除数据
dic.pop(c)
# 从检测列表中删除已发送完成的客户端
wlist.remove(c)
except ConnectionResetError:
c.close() # 关闭连接
dic.pop(c) # 删除要发送的数据
wlist.remove(c) # 从待检测的列表中删除
except BlockingIOError:#可能缓存满了 发不了
pass 
客户端:
 import socket

 c = socket.socket()

 c.connect(("192.168.11.210",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:
import asyncio
asyncio.coroutine()
from concurrent.futures import ThreadPoolExecutor def task():
print("read start")
with open(r"D:\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 内部是使用的是协程

I/O模型的更多相关文章

  1. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库

    在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...

  2. ASP.NET Core MVC/WebAPi 模型绑定探索

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  3. ASP.NET路由模型解析

    大家好,我又来吹牛逼了 ~-_-~ 转载请注明出处:来自吹牛逼之<ASP.NET路由模型解析> 背景:很多人知道Asp.Net中路由怎么用的,却不知道路由模型内部的运行原理,今天我就给大家 ...

  4. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  5. 探索ASP.NET MVC5系列之~~~4.模型篇---包含模型常用特性和过度提交防御

    其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...

  6. 隐马尔科夫模型python实现简单拼音输入法

    在网上看到一篇关于隐马尔科夫模型的介绍,觉得简直不能再神奇,又在网上找到大神的一篇关于如何用隐马尔可夫模型实现中文拼音输入的博客,无奈大神没给可以运行的代码,只能纯手动网上找到了结巴分词的词库,根据此 ...

  7. webapi - 模型验证

    本次要和大家分享的是webapi的模型验证,讲解的内容可能不单单是做验证,但都是围绕模型来说明的:首先来吐槽下,今天下午老板为自己买了套新办公家具,看起来挺好说明老板有钱,不好的是我们干技术的又成了搬 ...

  8. 谈谈一些有趣的CSS题目(二)-- 从条纹边框的实现谈盒子模型

    开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...

  9. 【NLP】蓦然回首:谈谈学习模型的评估系列文章(一)

    统计角度窥视模型概念 作者:白宁超 2016年7月18日17:18:43 摘要:写本文的初衷源于基于HMM模型序列标注的一个实验,实验完成之后,迫切想知道采用的序列标注模型的好坏,有哪些指标可以度量. ...

  10. 【NLP】揭秘马尔可夫模型神秘面纱系列文章(一)

    初识马尔可夫和马尔可夫链 作者:白宁超 2016年7月10日20:34:20 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无什么用场.直到学习自然语言处 ...

随机推荐

  1. jQuery 中的简单动画

    制作动画常用方法: show("速度")   显示元素   hide("速度")   隐藏元素   toggle()       切换效果 例如下jQuery代 ...

  2. Redis可视化工具 Redis Desktop Manager

    1.前言 从接触Redis也有两年,平时就使用它来做缓存层,它给我的印象就是很强大,内置的数据结构很齐全,加上Redis5.0的到来,新增了很多特色功能.而Redis5.0最大的新特性就是多出了一个数 ...

  3. Saltstack_使用指南02_远程执行-验证

    1. 主机规划 2. Master与哪些minion通信 2.1. Master与哪些minion正常通信 [root@salt100 ~]# salt '*' test.ping salt100: ...

  4. Vue SSR: 基本用法 (二)

    上一篇讲解了ssr的原理,这篇主要讲基本用法: 1.安装 npm install vue vue-server-renderer --save 我们将在整个指南中使用 NPM,但你也可以使用 Yarn ...

  5. koa 路由配置

    Koa 路由 路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET.POST 等) 组成的,涉及到应用如何响应客户端对某个网站节点的访问. 通俗的讲:路由就是根据不 ...

  6. Django-CRM项目学习(三)-stark的页面展示

    开始今日份整理,主要为stark组件的增删改以及model_form组件的使用以及form组件的回顾 1.list_display_link功能 功能:客制化字段进行跳转到指定的页面(编辑页面) 1. ...

  7. C#多线程与并行编程方面的电子书,中英文版本

    给大家共享一些C#多线程与并行编程方面的电子书,中英文版本的. 链接: 百度网盘地址 提取码: y99a

  8. vue diff 算法学习

    function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) { let oldStartIdx ...

  9. BZOJ3709 Bohater 贪心

    传送门 思路很妙-- 有个前提条件:血量无限,这样话肯定先打会回血的怪,再打会掉血的怪 对于会回血的怪,按照受到伤害的顺序从小往大打 对于会掉血的怪似乎并不是很好搞,考虑:将每一时刻的血量函数画出来, ...

  10. cmdb部署

    参考资料:https://github.com/guohongze/adminset 基础安装说明:1.基本要求:centos 7.2(1511) django 1.9.8(兼容Django1.11) ...