I/O模型
目录:
总结:
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模型的更多相关文章
- ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库
在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...
- ASP.NET Core MVC/WebAPi 模型绑定探索
前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...
- ASP.NET路由模型解析
大家好,我又来吹牛逼了 ~-_-~ 转载请注明出处:来自吹牛逼之<ASP.NET路由模型解析> 背景:很多人知道Asp.Net中路由怎么用的,却不知道路由模型内部的运行原理,今天我就给大家 ...
- 高性能IO模型浅析
高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking ...
- 探索ASP.NET MVC5系列之~~~4.模型篇---包含模型常用特性和过度提交防御
其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...
- 隐马尔科夫模型python实现简单拼音输入法
在网上看到一篇关于隐马尔科夫模型的介绍,觉得简直不能再神奇,又在网上找到大神的一篇关于如何用隐马尔可夫模型实现中文拼音输入的博客,无奈大神没给可以运行的代码,只能纯手动网上找到了结巴分词的词库,根据此 ...
- webapi - 模型验证
本次要和大家分享的是webapi的模型验证,讲解的内容可能不单单是做验证,但都是围绕模型来说明的:首先来吐槽下,今天下午老板为自己买了套新办公家具,看起来挺好说明老板有钱,不好的是我们干技术的又成了搬 ...
- 谈谈一些有趣的CSS题目(二)-- 从条纹边框的实现谈盒子模型
开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...
- 【NLP】蓦然回首:谈谈学习模型的评估系列文章(一)
统计角度窥视模型概念 作者:白宁超 2016年7月18日17:18:43 摘要:写本文的初衷源于基于HMM模型序列标注的一个实验,实验完成之后,迫切想知道采用的序列标注模型的好坏,有哪些指标可以度量. ...
- 【NLP】揭秘马尔可夫模型神秘面纱系列文章(一)
初识马尔可夫和马尔可夫链 作者:白宁超 2016年7月10日20:34:20 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无什么用场.直到学习自然语言处 ...
随机推荐
- June. 24th 2018, Week 26th. Sunday
Beautiful things don't ask for attention. 真正美丽的东西,并不会刻意寻求别人的注目. From The Secret Life of Walter Mitty ...
- Spring系列-SpringBoot 学习路径
学习spring boot 已经有很长一段时间,与其说学习,不如说是使用. 在过去的很长时间我一直奉行实用主义,任何技术我都是在应用中使用,很少是因为为了学习而学习. 当然,有那么几次心血来潮,去专门 ...
- 【Python 补充01】Python运算符
Python运算符 举个简单的例子 4 +5 = 9 . 例子中,4 和 5 被称为操作数,"+" 称为运算符. 1.算术运算符 + - * / # 加减乘除 % # 取模(返回除 ...
- Hive:ORC File Format存储格式详解
一.定义 ORC File,它的全名是Optimized Row Columnar (ORC) file,其实就是对RCFile做了一些优化. 据官方文档介绍,这种文件格式可以提供一种高效的方法来存储 ...
- Loj #2495. 「AHOI / HNOI2018」转盘
Loj #2495. 「AHOI / HNOI2018」转盘 题目描述 一次小 G 和小 H 原本准备去聚餐,但由于太麻烦了于是题面简化如下: 一个转盘上有摆成一圈的 \(n\) 个物品(编号 \(1 ...
- C++ 既有约定
Pascal 拼写法: 函数名MultiplyNumbers(),每个单词的首字母都大写 驼峰拼写法: 变量名 firstNumber,第一个单词的首字母采用小写 匈牙利表示法: iFirstNumb ...
- Django模板语言(Template)
1.变量 变量相关用 { { } } 逻辑相关用{% %} 2.Filter过滤器 (1)default 如果一个变量是false或者为空,使用给定的默认值. 否则,使用变量的值. {{ va ...
- OpenStack-Neutron(5)
一. Neutron 概述 SDN(software-defined networking)软件定义网络,其所具有的灵活性和自动化优势使其成为云时代网络管理的主流. Neutron的设计目标是实现“网 ...
- 让多个HTML页面 使用 同一段HTML代码
需求背景 一个网站有多个网页:一个网页,可以分为很多部分,举个例子,下面是一个特别简单的网页结构: 一般情况下,footer都是用于标识网站的相关信息(备案.联系方式.制作方),每一个页面都是相 ...
- android调用plus报错plus is not defined
由于plus 加载需要时间,我们使用plus 的时候应该提前判断是否已经加载好,添加监听 document.addEventListener("plusready",functio ...