python并发编程之IO阻塞基础知识点
IO模型
IO阻塞模型分类:
- 阻塞IO
- 非阻塞IO
- 多路复用IO
- 异步IO(爬虫阶段)
- 信号驱动IO(了解)
1、阻塞IO模型
socket模块默认是阻塞的,一个读操作流程如下:

问题:
同一时间只能服务一个客户端
解决办法:
1. 多线程
优点:如果并发量不高,效率是较高的,因为每个客户端都有单独线程来处理
缺点:不可能无限的开启线程,线程也需要占用资源
2. 多进程
优点:可以多个CPU并行处理
弊端:占用资源非常大,一旦客户端稍微多一点,立马就慢了
3.线程池
优点:保证了服务器正常运行,还帮你负责创建和销毁线程,以及任务分配
缺点:一旦并发量超出最大线程量,就只能等签名的运行完毕。
4. 协程
优点:不需要创建一段线程,也不需要在线程间做切换,没有数量限制
缺点:不能利用多核优势
结果:真正倒是效率低的是阻塞问题,但上述办法并没有真正的解决阻塞问题。
2、非阻塞IO模型
遇到IO操作也不阻塞,会继续执行。意味着即使遇到IO操作CPU执行权也不会被剥夺
从图中看出,非阻塞的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阻塞基础知识点的更多相关文章
- Python并发编程之IO模型
目录 IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) IO多路复用 异步IO IO模型比较分析 selectors模块 一.IO模型介绍 Stevens ...
- python并发编程之IO模型,
了解新知识之前需要知道的一些知识 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调 ...
- python并发编程之IO模型(Day38)
一.IO模型介绍 为了更好的学习IO模型,可以先看同步,异步,阻塞,非阻塞 http://www.cnblogs.com/linhaifeng/articles/7430066.html#_label ...
- 33 python 并发编程之IO模型
一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非 ...
- 五 python并发编程之IO模型
一 IO模型介绍 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问 ...
- python并发编程之IO模型(实践篇)
一.阻塞IO 介绍略(请看概念篇) 二.非阻塞IO 在非阻塞式IO中,用户进程需要不断的主动询问kernel数据准备好了没有 # 服务端 import socket import time serve ...
- 第十篇.6、python并发编程之IO模型
一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非 ...
- 第 13 章 python并发编程之io模型
一.IO模型介绍 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问 ...
- 38、python并发编程之IO模型
目录: 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 异步IO(Asynchron ...
随机推荐
- MySQL 笔记整理(11) --怎么给字符串字段加索引?
笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 11) --怎么给字符串字段加索引? 日常工作中的登录系统,你很可能会使 ...
- spring通知执行的顺序
点击下载本示例相关代码 关于spring aop的具体使用,暂时不在这里讲解,后面会特定来讲解,本次主要探讨spring中通知执行的顺序. spring中通知分为以下几种: before:前置通知,在 ...
- Java开发笔记(八十四)文件与目录的管理
程序除了处理内存中的数据结构,还要操作磁盘上的各类文件,这里的磁盘是个统称,泛指可以持久保留数据的存储介质,包括但不限于:插在软驱中的软盘.固定在机箱中的硬盘.插在光驱中的光盘.插在USB接口上的U盘 ...
- H5、C3、ES6的新特性
H5的新特性 1.语义化标签 有利于SEO,有助于爬虫抓取更多的有效信息,爬虫是依赖于标签来确定上下文和各个关键字的权重. 语义化的HTML在没有CSS的情况下也能呈现较好的内容结构与代码结构 方便其 ...
- ServiceStack.Redis 请求次数6000次异常
Redis是一个非常NB的内存级的数据库,我们可以把很多”热数据“(即读写非常多的数据)放入其中来操作,这样就减少了和关系型数据库(如SqlServer/My Sql等)之间的交互,程序的响应速度也大 ...
- 阅读笔记:基础知识(Java篇)
1. GC机制(垃圾回收机制) 找到垃圾的方法:引用计数法.可达性分析法 回收垃圾的方法:标记清除算法.复制算法.标记整理法.分代算法 2. JVM内存划分 线程私有:程序计数器.JVM虚拟机栈.本地 ...
- vue.js 学习笔记3——TypeScript
目录 vue.js 学习笔记3--TypeScript 工具 基础类型 数组 元组 枚举 字面量 接口 类类型 类类型要素 函数 函数参数 this对象和类型 重载 迭代器 Symbol.iterat ...
- rocketmq简单消息发送
有以下3种方式发送RocketMQ消息 可靠同步发送 reliable synchronous 可靠异步发送 reliable asynchronous 单向发送 one-way transmissi ...
- Hive分桶
1.简介 分桶表是对列值取哈希值的方式将不同数据放到不同文件中进行存储.对于hive中每一个表,分区都可以进一步进行分桶.由列的哈希值除以桶的个数来决定数据划分到哪个桶里. 2.适用场景 1.数据抽样 ...
- Redis 主从复制原理及雪崩 穿透问题
定义: Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发工作由VMw ...