在socket的通信中,recv,accept,recvfrom(UDP协议接收信息)这些阶段由于需要收到信息,才能继续下面的代码,所以这些阶段叫做阻塞,类似于
我们python变成中的input函数,time.sleep方法,在socket通信中,这些阻塞会使进程进入到阻塞状态,下次再进入运行状态时要消耗内存,所以解决
阻塞可以提高我们代码的执行效率和节省内存空间。下面以访问文件为例,看几种典型的IO模式

一、阻塞IO
经历了两个阻塞阶段
1.发送方:发出去的请求之后等待回应
2.接收方:收到请求,整理数据,从内核拷贝到进程里
这是最原始的IOmodel,记住这两个阻塞阶段,后面的IO模型都是基于这两点做该进的。

当然,我们可以开起多线程,多进程的方式,在阻塞的时间里处理其他的事情,但是当线程、进程开到很多的时候会占用系统资源,降低系统响应速率。
当规模比较大时,这种方法就不适合选择了。

二、非阻塞IO

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.setblocking(False)
sk.listen()
conn_l = [] # 已连接的客户端列表
del_conn = []
while True:
try:
conn,addr = sk.accept() #不阻塞,但是没人连我会报错
print('建立连接了:',addr)
conn_l.append(conn) #将连接过的加入列表,便于提取下次客户端第二次发送信息
except BlockingIOError:
for con in conn_l:
try:
msg = con.recv(1024) # 非阻塞,如果没有数据就报错
if msg == b'':
del_conn.append(con)
continue
print(msg)
con.send(b'byebye')
except BlockingIOError:pass
for con in del_conn:
con.close()
conn_l.remove(con)
del_conn.clear()

server端

import time
import socket
from threading import Thread def func():
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
time.sleep(0.1) # 模拟阻塞
sk.send(b'hello')
time.sleep(0.5) # 模拟接收消息过程
msg = sk.recv(1024)
print(msg)
sk.close() for i in range(10):
t = Thread(target=func)
t.start()

client端

依次启动服务端,客户端 服务端
收到客户端连接并加入conn_l列表,由于客户端设置了一个发消息之前设置了一个sleep,并且服务端set.blocking=False,
服务端while循环时未取到accept会进入注释为‘1’的异常处理,查询conn_1后,接收到客户端完成sleep发来的信息。但此时会接收到一系列的
b'',(同时未取到信息会报错,捕捉并且不作处理)因为客户端已经发送完成,没有消息了,服务端recv都是空,应该判断msg是否为b'',
并将这个连接加入到删除列表,循环完成后删除。

但是用while轮询时,非常占用内存,导致系统处理变慢,响应速率降低。

三、IO多路复用

IO多路复用模型是socket服务端借助了操作系统来完成的,操作系统会监听访问者,一旦收到连接请求,操作系统来给socket服务端提供信号,让其进入accept阶段,向下继续执行,使其变为非阻塞状态,同时也会将文件拷贝至进程,让其recv。这种用于socket端比较多的情况,因为比起阻塞IO,多路复用增加了一个系统与socket之间的相互通信。但是如果监听的socket较多的话,效率还是很快的。

import select   # select模块是操作系统用来监听的模块
import socket sk = socket.socket()
sk.bind(('127.0.0.1',8000))
sk.setblocking(False)
sk.listen() read_lst = [sk] # 将需要监听的sk加入列表
while True: # [sk,conn]
r_lst,w_lst,x_lst = select.select(read_lst,[],[]) # 返回的是三个值,分别为是哪个socket可读,可写,可改
# 一旦有文件可以读取,就会返回该socket的地址
for i in r_lst:
if i is sk:
conn,addr = i.accept()
read_lst.append(conn) # socket可连接的客户端链接地址
else:
ret = i.recv(1024)
if ret == b'':
i.close()
read_lst.remove(i)
continue
print(ret)
i.send(b'goodbye!')

服务端server

相较于非阻塞IO,可以监听多个socket,并且不用多次轮询,优化了内存使用

补充一点,代码中的select是windows系统用的,还有Linux的poll模块,监听的数量要比select多,以及Linux的epolled模块,不仅起到监听socket对象的作用,而且还会给每个对象加上一个回调函数。windows中的selector模块和其作用相似。

在监听的对象成百上千时,由于数据类型是列表,数量越多查询速度越慢,但是使用epoll一旦准备好可以读取,可以调用它的回调函数直接来发送信号给socket,速率更高。

四、异步IO

异步IO原理是 用户端发送读取请求,不进入阻塞,可以做不相干的业务逻辑,将请求发给操作系统执行,操作系统完成文件的recv和提取到进程的过程,用户端直接读取。

但由于python端没有可以直接操作系统的接口,所以目前大部分异步IO都是由C语言完成。

常见IO模型的更多相关文章

  1. 京东数科二面:常见的 IO 模型有哪些?Java 中的 BIO、NIO、AIO 有啥区别?

    IO 模型这块确实挺难理解的,需要太多计算机底层知识.写这篇文章用了挺久,就非常希望能把我所知道的讲出来吧!希望朋友们能有收货!为了写这篇文章,还翻看了一下<UNIX 网络编程>这本书,太 ...

  2. 京东数科面试真题:常见的 IO 模型有哪些?Java 中的 BIO、NIO、AIO 有啥区别?

    本文节选自<Java面试进阶指北 打造个人的技术竞争力> 面试中经常喜欢问的一个问题,因为通过这个问题,面试官可以顺便了解一下你的操作系统的水平. IO 模型这块确实挺难理解的,需要太多计 ...

  3. python并发编程之IO模型 同步 异步 阻塞 非阻塞

    IO浅谈 首先 我们在谈及IO模型的时候,就必须要引入一个“操作系统”级别的调度者-系统内核(kernel),而阻塞非阻塞是跟进程/线程严密相关的,而进程/线程又是依赖于操作系统存在的,所以自然不能脱 ...

  4. Linux下常见的IO模型

    前言 阻塞IO(blocking IO) 非阻塞IO(nonblocking IO) IO复用(IO multiplexing) 异步IO(asynchronous IO (the POSIX aio ...

  5. 高性能IO模型浅析

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

  6. Linux下5种IO模型的小结

    概述 接触网络编程,我们时常会与各种与IO相关的概念打交道:同步(Synchronous).异步(ASynchronous).阻塞(blocking)和非阻塞(non-blocking).关于概念的区 ...

  7. 操作系统IO模型

    操作系统IO模型 声明:如下内容是根据APUE和mycat两本著作中关于I/O模式的一些内容加上自己的一些理解整理而成,仅供学习使用. 本节内容 UNIX下可用的五种I/O模型 三种I/O模型 Rea ...

  8. 服务器端高性能的IO模型 转自酷勤网

    服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(BlockingIO):即传统的IO模型. (2)同步非阻塞IO(Non-blockingIO):默认创建的soc ...

  9. 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出 ...

随机推荐

  1. 【MySQL】InnoDB 内存管理机制 --- Buffer Pool

    InnoDB Buffer Pool 是一块连续的内存,用来存储访问过的数据页面 innodb_buffer_pool_size 参数用来定义 innodb 的 buffer pool 的大小 是 M ...

  2. 算法(第四版)C# 习题题解——2.4

    写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 查找更方便的版本见:https ...

  3. Gradle目录结构详解

    环境:window 7 64 Gradle 版本: gradle 3.0 创建文件夹,并初始化 mkdir gradle_dir && cd gradle_dir gradle ini ...

  4. 271. 杨老师的照相排列【线性DP】

    杨老师希望给他的班级拍一张合照. 学生们将站成左端对齐的多排,靠后的排站的人数不能少于靠前的排. 例如,12名学生(从后向前)可以排列成每排5,3,3,1人,如下所示: X X X X X X X X ...

  5. Redis 集群版

    1.# yum install ruby -y 1.1 后面需要用到ruby脚本 2.# yum install rubygems -y 1.1 安装ruby包管理器 3.# gem install ...

  6. Java 连接 MySQL 数据库

    最近想学习一下 Java 连接 MySQL 数据库,于是有了这样的一些问题&解决办法. 首先是解决 JDBC(Java Data Base Connectivity)驱动问题,因为默认安装的J ...

  7. 20165306 Exp2 后门原理与实践

    20165306 Exp2 后门原理与实践 实验内容 (1)使用netcat获取主机操作Shell,cron启动 (2)使用socat获取主机操作Shell, 任务计划启动 (3)使用MSF mete ...

  8. 20165306 Exp0 Kali安装 Week1

    20165306 Exp0 Kali安装 Week1 实验要求 Kali 下载 安装 网络 共享 软件源 步骤一.下载Kali 根据网址https://www.kali.org/ 下载kali 点击 ...

  9. java.io.IOException: Attempted read from closed stream

    前言: 代码如下,执行的时候提示"java.io.IOException: Attempted read from closed stream." public static JS ...

  10. ES6多层解构

    const info = { person: { name: 'xiaobe', other: { age: 22, } }, song: 'rolling', } // 解构person的内容 co ...