五 IO模型

常用的IO模型有4种:

  • 阻塞IO
  • 非阻塞IO
  • IO多路复用
  • 异步IO

不常用的有:

  • 驱动信号

5.1 阻塞IO、非阻塞IO

  • 阻塞IO:进程不能做其他的事情
  • 非阻塞IO:等待数据无阻塞

阻塞IO

阻塞IO就是全程阻塞,其中,全程指的是等待数据和 数据从内核态拷贝到用户态。

全程阻塞就是以上两个步骤都阻塞。如图:

系统调用两个阶段:

  • wait for data:阻塞
  • copy data:阻塞

非阻塞IO

非阻塞IO是部分阻塞,

等待数据时不会阻塞,而是在固定时间内循环发起系统调用,请求不到做自己的事情,等待下次请求,

而数据从内核态拷贝到用户态还是阻塞的。如图:

系统调用两个阶段:

  • wait for data:非阻塞
  • copy data:阻塞

优点:

等待数据无阻塞

缺点:

1.系统调用发送太多

2.数据不是即时接收的

ps:socket设置socket对象.setblocking(False) 设置阻塞状态为非阻塞

5.2 IO多路复用

IO多路复用:全程阻塞,监听多个链接

系统调用两个阶段:

  • wait for data:阻塞
  • copy data:阻塞

实现IO多路复用的常用方式有:

  • select
  • poll
  • epoll

原理

基本原理:

通过select/poll/epoll函数不断轮询所负责的所有socket套接字,当某个socket套接字有数据到达,就通知用户进程。

特点:

就是单个process可以同时处理多个网络连接的IO,

ps:不同的操作系统提供的函数不同:

windows系统: select

linux系统: select、poll、epoll

select模块

系统调用通过select模块完成wait for data的工作

示例:

select监听多个socket对象(sock是socket对象),实现并发

r, w, e = select.select([sock,], [], [])  # 等待链接
for obj in r:
conn, addr = obj.accept()

示例升级:

inputs = [sock,]
r, w, e = select.select(inputs, [], []) # inputs监听有变化的套接字 inputs=[sock,conn1,conn2,...]
for obj in r: # 第一次[sock,] 第二次[conn1,]
if obj == sock: # 如果返回的r = sock,说明有连接请求
conn, addr = obj.accept()
inputs.append(conn) # inputs=[sock, conn1, conn2]
else: # 否则,可以接收数据了
data = obj.recv(1024)

ps:关于文件描述符的tips(socket套接字)

1.每一个套接字对象的本质就是一个非零整数,不会变(fb=4)

<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM,
proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51963)>

2.收发数据的时候,对于接收端而言,数据先到内核空间,然后copy到用户空间,同时内核空间的数据被清空

3.根据TCP协议,当发送端接收到接收端的确认信息后,清空内核空间的数据,否则不清空

select、poll、epoll

select:

  • 每次调用select都要将所有的fd(文件描述符),copy到你的内核空间
  • 遍历所有的fd,是否有数据访问
  • 最大连接数(1024),超出链接不再监听

ps:select的特点也是其缺点,会导致效率下降:

poll:

  • 每次调用select都要将所有的fd(文件描述符),copy到你的内核空间
  • 遍历所有的fd,是否有数据访问
  • 最大连接数没有限制

epoll:

  • 不同于select和poll只有一个函数,epoll通过三个函数实现实现轮询socket:

    • 第一个函数:创建epoll句柄:将所有的fd(文件描述符),copy到你的内核空间,只copy一次
    • 回调函数:为所有fd绑定一个回调函数,一旦有数据访问,触发回调函数,回调函数将fd放入一个链表中
    • 第三个函数:判断链表是否为空
  • epoll最大连接数没有上线

ps:回调函数

某一个函数或者某一个动作,成功完成之后,会触发的函数

selectors模块

selectors是select的升级版

selectors基于select模块实现IO多路复用,调用语句selectors.DefaultSelector()创建selecters对象,特点是根据平台自动选择最佳IO多路复用机制,调用顺序:epoll > poll > select

import selectors
import socket sel = selectors.DefaultSelector() # 根据平台自动选择最佳IO多路复用机制 def accept(sock, mask):
conn, addr = sock.accept()
sel.register(conn, selectors.EVENT_READ, read) # 将conn和read()注册到一起,当conn有变化时执行read() def read(conn, mask):
try:
data = conn.recv(1000)
print(data.decode('utf8'))
inputs = input('>>:').strip()
conn.send(inputs.encode('utf8'))
except Exception:
sel.unregister(conn)
conn.close() sock = socket.socket()
sock.bind(('127.0.0.1', 8080))
sock.listen(100)
sock.setblocking(False) # 设置为非阻塞IO sel.register(sock, selectors.EVENT_READ, accept) # 将sock和accept()注册到一起,当sock有变化时执行accept() while True:
events = sel.select() # 监听 [(key1,mask1),(key2),(mask2)]
for key, mask in events:
func = key.data # 1 key.data就是accept # 2 key.data就是read
obj = key.fileobj # 1 key.fileobj就是sock # 2 key.fileobj就是conn func(obj, mask) # 1 accept(sock,mask) # 2read(conn,mask)

5.3 同步IO、异步IO

同步IO

只要系统调用中存在阻塞就是同步IO,

所以,阻塞IO、非阻塞IO、IO多路复用都是同步IO

异步IO

全程无阻塞,实现复杂

系统调用两个阶段:

  • wait for data:非阻塞
  • copy data:非阻塞

并发编程(三) IO模型的更多相关文章

  1. 【并发编程】IO模型

    一.要点回顾 为了更好地了解IO模型,我们需要先回顾下几个概念:同步.异步.阻塞.非阻塞 同步: 一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行.就是在发出一个功能调用时,在没 ...

  2. Python之网络编程之并发编程的IO模型,

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

  3. python 并发编程 多路复用IO模型

    多路复用IO(IO multiplexing) 这种IO方式为事件驱动IO(event driven IO). 我们都知道,select/epoll的好处就在于单个进程process就可以同时处理多个 ...

  4. python 并发编程 阻塞IO模型

    阻塞IO(blocking IO) 在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样: 当用户进程调用了recvfrom这个系统调用,kernel内核就 ...

  5. python 并发编程 异步IO模型

    异步IO(Asynchronous I/O) Linux下的asynchronous IO其实用得不多,从内核2.6版本才开始引入.先看一下它的流程: 用户进程发起read操作之后,立刻就可以开始去做 ...

  6. x86-TSO : 适用于x86体系架构并发编程的内存模型

    Abstract : 如今大数据,云计算,分布式系统等对算力要求高的方向如火如荼.提升计算机算力的一个低成本方法是增加CPU核心,而不是提高单个硬件工作效率. 这就要求软件开发者们能准确,熟悉地运用高 ...

  7. Java并发编程三个性质:原子性、可见性、有序性

      并发编程 并发程序要正确地执行,必须要保证其具备原子性.可见性以及有序性:只要有一个没有被保证,就有可能会导致程序运行不正确  线程不安全在编译.测试甚至上线使用时,并不一定能发现,因为受到当时的 ...

  8. Java并发编程-Java内存模型

    JVM内存结构与Java内存模型经常会混淆在一起,本文将对Java内存模型进行详细说明,并解释Java内存模型在线程通信方面起到的作用. 我们常说的JVM内存模式指的是JVM的内存分区:而Java内存 ...

  9. Python并发编程之IO模型

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

随机推荐

  1. ubuntu 中安装memcache,并给出一个简单的实例·

    Memcache分为两部分,Memcache服务端和客户端.Memcache服务端是作为服务来运行的,所有数据缓存的建立,存储,删除实际上都是在这里完成的.客户端,在这里我们指的是PHP的可以调用的扩 ...

  2. org.hibernate.UnknownEntityTypeException: Unable to locate persister: com.hibernate2.pojo.News at org.hibernate.internal.SessionFactoryImpl.locateEntityPersister(SessionFactoryImpl.java:797)

    使用的是hibernate5的方法: ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySetti ...

  3. es6 很简单

    es6出了许多好的,优秀的特性.下面列举一些常用的 其实这些特性都很好理解,一两句话就可以表达出来看.主要是对旧的写法的一种改进. function  加了一些语言糖,传参更方便 class      ...

  4. DBGridEH序号的自动生成

    序号的自动生成1.定义变量  private         maxno:integer;  public        bmodified:boolean;2.写函数  function max(c ...

  5. Cannot create file"C:\Users\LML\AppData\Local\Temp\EditorLineEnds.ttr"。另一个程序正在使用此文件,进程无法访问。

    不能二次启动,每次开机第一次都ok,出于习惯,总是想试试第二次打开软件是否正常,结果不出所料,出现了“Cannot create file"C:\Users\LML\AppData\Loca ...

  6. nowcoder 203J Graph Coloring I(dfs)

    题目链接 题目描述 修修在黑板上画了一些无向连通图,他发现他可以将这些图的结点用两种颜色染色,满足相邻点不同色. 澜澜不服气,在黑板上画了一个三个点的完全图.修修跟澜澜说,这个图我能找到一个简单奇环. ...

  7. 多态在编译器是无法确定引用类型的是哪个子类 可以用 instanceof 在运行期判断

  8. Latex编译过程中遇到的奇奇怪怪的问题及解决方案

    标签(空格分隔): 杂七杂八的问题 有必要写一个博文记录自己在Latex编译时遇到的各种问题,希望可以帮到遇到同样错误的亲故.讲真,一直没有系统的学习Latex,都是投哪个会直接拿那个会的模板来套,然 ...

  9. div布局小技巧

    第一: 多个div整齐排列在外层div中,如图: 看到所有小的div的前后左右间隔都相等.假定已经制作好上述单元div控件.在外层大div中循环开始创建它们. for (var i=0; i < ...

  10. 使用mshta.exe绕过应用程序白名单(多种方法)

      0x00 简介 很长一段时间以来,HTA文件一直被web攻击或在野恶意软件下载程序用作恶意程序的一部分.HTA文件在网络安全领域内广为人知,从红队和蓝队的角度来看,它是绕过应用程序白名单有价值的“ ...