IO模型

  解决IO问题的方式方法
  问题是:IO操作阻塞程序执行
  解决的也仅仅是网络IO操作
 
  一般数据传输经历的两个阶段,如图:

  IO阻塞模型分类:

  1. 阻塞IO
  2. 非阻塞IO
  3. 多路复用IO
  4. 异步IO(爬虫阶段)
  5. 信号驱动IO(了解)

1、阻塞IO模型

  socket模块默认是阻塞的,一个读操作流程如下:

  问题:

    同一时间只能服务一个客户端

  解决办法:

    1. 多线程

      优点:如果并发量不高,效率是较高的,因为每个客户端都有单独线程来处理

      缺点:不可能无限的开启线程,线程也需要占用资源

    2. 多进程

      优点:可以多个CPU并行处理

      弊端:占用资源非常大,一旦客户端稍微多一点,立马就慢了

    3.线程池

      优点:保证了服务器正常运行,还帮你负责创建和销毁线程,以及任务分配

      缺点:一旦并发量超出最大线程量,就只能等签名的运行完毕。

    4. 协程

      优点:不需要创建一段线程,也不需要在线程间做切换,没有数量限制

      缺点:不能利用多核优势

    结果:真正倒是效率低的是阻塞问题,但上述办法并没有真正的解决阻塞问题。

2、非阻塞IO模型

  遇到IO操作也不阻塞,会继续执行。意味着即使遇到IO操作CPU执行权也不会被剥夺

  方法:设置socket使其变为non-blocking,即server.setblocking(False),具体流程如下:

  从图中看出,非阻塞的recv系统调用之后,进程没有被阻塞,操作系统立马把结果返回给进程,如果数据还没准备好,则抛出异常,进程可以去做其他的事,然后在发起recv系统调用,重复上述过程(这个过程通常被称为轮询),一直到数据准备好,再拷贝数据到进程进行数据处理。需要注意,拷贝数据的整个过程,进程仍然是属于阻塞状态。

  缺点: 占用CPU太多,原因是需要无限的循环去向操作系统拿数据。

import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('127.0.0.1', ))
server.listen()
server.setblocking(False)
# 所有客户端的socket
conns = []
# 所有需要返回数据的客户端
send_cs = [] while True:
try:
conn, client_addr = server.accept()
print(client_addr,'已连接')
conns.append(conn)
except BlockingIOError:
# 接收数据
for conn in conns[:]:# 和conns.copy()一样,原因:迭代过程不能删除元素
try:
data = conn.recv()
print(data)
send_cs.append((data, conn))
# send也是IO操作,在一些极端情况下,如系统缓存满了,肯定也会抛出异常
# 所以,send要单拿出来处理
except BlockingIOError:
continue
except ConnectionResetError:
conn.close()
conns.remove(conn)
# 发送数据
for item in send_cs[:]:
data, conn = item
try:
conn.send(data.upper())
# 如果发送成功就把数据从列表中删除
send_cs.remove(item)
except BlockingIOError: # 如果缓冲区满了 就下次再发
continue
except ConnectionResetError:
conn.close()
send_cs.remove(item)
conns.remove(conn)

服务端代码

3、多路复用IO

  用一个线程来处理并发所有的客户端。

  需要使用select模块,select原理:把所有的socket交给select,select会不断轮询所负责的所有socket,当某个socket有数据到达,就通知进程继续执行后面代码。

  流程:程序发起一个select调用,select使整个进程阻塞,直到有socket准备就绪,select就返回,这个时候进程在调用read操作,直接从缓冲中把数据拷贝到进程。流程图如下:

import socket
import select server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", ))
server.listen() r_list = [server] # 监测是否收到数据的客户端
w_list = [] # 监测是否需要发送数据的客户端
x_list = [] # 用来发送数据
data_dic = {} while True:
readables, writeables, _ = select.select(r_list, w_list, x_list)
# 接收数据以及建立连接
for conn in readables:
if conn == server:
new_conn, _ = conn.accept()
r_list.append(new_conn)
else:
try:
data = conn.recv()
if not data:
conn.close()
r_list.remove(conn)
continue
print(data)
# 发送数据
w_list.append(conn)
data_dic[conn] = data
except ConnectionResetError:
conn.close()
r_list.remove(conn)
# 发送数据
for conn in writeables:
try:
conn.send(data_dic[conn].upper())
except ConnectionResetError:
conn.close()
finally:
data_dic.pop(conn)
w_list.remove(conn)

服务端代码

import socket
import threading
from threading import Thread def communication():
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', ))
while True:
msg = "%s say hello for you"%threading.current_thread()
if not msg:
continue
client.send(msg.encode("utf-8"))
data = client.recv()
print(data.decode("utf-8")) for i in range():
Thread(target=communication).start()

客户端代码

  强调:select的优势在于可以处理多个连接,并不适用于单个连接

  优点:占用资源少,不消耗太多CPU,同时能够为多个客户端提供服务。(适用于简单的事件驱动服务器)

  缺点:需要消耗大量时间区轮询各个socket,更好的选择时epoll,其次把事件探测和响应夹杂在一起,耦合性增加

python并发编程之IO阻塞基础知识点的更多相关文章

  1. Python并发编程之IO模型

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

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

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

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

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

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

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

  5. 五 python并发编程之IO模型

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

  6. python并发编程之IO模型(实践篇)

    一.阻塞IO 介绍略(请看概念篇) 二.非阻塞IO 在非阻塞式IO中,用户进程需要不断的主动询问kernel数据准备好了没有 # 服务端 import socket import time serve ...

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

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

  8. 第 13 章 python并发编程之io模型

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

  9. 38、python并发编程之IO模型

    目录: 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 异步IO(Asynchron ...

随机推荐

  1. 菜鸟先飞C#学习总结(一)

    一.第一个程序Hellow Word using System; //using 关键字用于在程序中包含 System 命名空间. 一个程序一般有多个 using 语句. using System.C ...

  2. Java HashMap 使用了未经检查或不安全的操作

    今天在做接口测试的时候使用了Java中的Map(java 所知胜少,因项目需要提供示例),不扯犊子了,我们直接看一个代码文件名:Test.java: import java.util.ArrayLis ...

  3. JavaScript 运行机制 (Event Loop)

    单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务.如果前一个任务耗时很长,后一个任务就不得不一直等着. 所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步 ...

  4. WebGL或OpenGL关于模型视图投影变换的设置技巧

    目录 1. 具体实例 2. 解决方案 1) Cube.html 2) Cube.js 3) 运行结果 3. 详细讲解 1) 模型变换 2) 视图变换 3) 投影变换 4) 模型视图投影矩阵 4. 存在 ...

  5. 升鲜宝V2.0_生鲜配送行业,对生鲜配送系统开发与实施的深度对比与思考_升鲜宝生鲜配送系统_15382353715_余东升

               升鲜宝V2.0_生鲜配送行业,对生鲜配送系统开发与实施的深度对比与思考_升鲜宝生鲜配送系统_15382353715_余东升 笔者从事生鲜配送软件开发接近10年,前前后后研究了很多 ...

  6. java.sql.SQLException: The server time zone value '???ú±ê×??±??' is unrecognized or represents more than one time zone.

    [报错信息] [百度翻译] 服务器时区值'???ú±ê×??±??'无法识别或表示多个时区.如果要利用时区支持,必须配置服务器或JDBC驱动程序(通过ServerTimeZone配置属性),以使用更具 ...

  7. Android视频录制从不入门到入门系列教程(三)————视频方向

    运行Android视频录制从不入门到入门系列教程(二)————显示视频图像中的Demo后,我们应该能发现视频的方向是错误的. 由于Android中,Camera给我们的视频图片的原始方向是下图这个样子 ...

  8. Spring AOP 整理笔记

    一.AOP概念 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. 利用AOP可以对业务逻辑的各 ...

  9. HTTP中GET和POST的区别主要是那些,面试中可以加分的该说那些?

    面试回答: GET请求在URL中传送的参数是有长度限制的,而POST没有. GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息. GET参数通过URL传递,POST放在Re ...

  10. [20190417]隐含参数_SPIN_COUNT.txt

    [20190417]隐含参数_SPIN_COUNT.txt--//在探究latch spin计数之前,先简单探究_SPIN_COUNT.实际上oracle现在版本latch spin的数量不再是200 ...