博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python IO模型
阅读量:5103 次
发布时间:2019-06-13

本文共 2469 字,大约阅读时间需要 8 分钟。

之前学到gevent 遇到IO操作,自动切换

对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,它会经历两个阶段:

  • 1 等待数据准备 (Waiting for the data to be ready)
  • 2 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)

记住这两点很重要,因为这些IO Model的区别就是在两个阶段上各有不同的情况。

IO模型

  • 阻塞IO
  • 非阻塞IO
  • IO多路复用(监听多个连接)
  • 异步IO
  • 驱动信号

1 阻塞IO blocking

默认的socket是阻塞的,任务是串行执行的

一个典型的读操作流程:

wait data和copy data的过程中都是在等待的,也就是阻塞的。
658994-20170510134539363-678294823.gif

内核态--用户态

操作系统操作的

数据存放在内核空间(数据缓冲区),操作系统把内核空间中的数据传到用户空间

数据准备阶段

accept发起系统调用,用户态转换成内核态

等待数据wait for data、copy data from kernal to user
都是阻塞,就是全程阻塞,在没有到达用户态的时候,都是阻塞

2 非阻塞IO nonblocking

可以通过设置socket的编程unblocking,sock.setblocking(True)

658994-20170510135836113-1643938007.gif

sock.setblocking(False) 这个没有连接,立刻报错

会立即返回是否已经连接了

wait data 不是阻塞的

从内核态拷贝数据 copy data到用户态的时候是阻塞的

  • 优点:不用等待数据 ,在发起系统调用的过程中是自己的时间
  • 缺点:一直发起系统调用,拿到的数据不是实时的

3 IO多路复用 select

IO 多路复用的本质就是非阻塞IO,它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程

658994-20170510141411472-472418406.gif

面试中的比较多

把等待数据的过程分成了两部分:

  • select 替代看wait for data return readable代表收到数据
  • recv已经获得了数据

select 可以连接多个套接字对象,

r,w,e = select.select([socket,],[],[])

socketserver是threading和select共同实现的,利用了多线程和IO多路复用

select是在监听,监听的是有变化的套机子

第一次监听的是sock对象,第二次连接的是conn

socket是一个文件描述符,fd是一个整数

select是基于IO操作,节省时间

基于IO多路复用的socket 多并发聊天

客户端select机制

import socketimport selectimport timesock = socket.socket()sock.bind(("127.0.0.1",8810))sock.listen(5)sock.setblocking(False)inputs = [sock,]  # 监听的列表while 1:    r,w,e = select.select(inputs,[],[])  # 监听有变化的套接字,inputs  = [socket,conn1,conn2...]    for obj in r:        if obj==sock:  # 第一次用[socket],第二次[conn]            conn,addr = obj.accept()            print("conn",conn)            inputs.append(conn) #        else:            data = obj.recv(1024)            print(data.decode("utf-8"))            send_data = input(">>>")            obj.send(send_data.encode("utf-8"))

客户端

import socketsock = socket.socket()sock.connect(("127.0.0.1", 8810))while 1:    data = input(">>>")    sock.send(data.encode("utf-8"))    recv_data = sock.recv(1024)    print(recv_data.decode("utf-8"))sock.close()

测试结果:

658994-20170510143833519-2091887821.jpg

有两个通道,socket是建立连接的,conn是进行通信的管道。sock对象是不变的。

关于文件描述符(套接字对象):

  • 是非零整数,不会变(fd=xxx,xxx是一个整数,filedescription)
  • 收发数据的时候,对于接收端而言,数据先到内核空间,然后copy到用户空间,同时内核空间的数据清空(内核空间和数据空间都是内存中分配的)
  • 发送端的时候,TCP的三次握手没有应答,数据不清空

IO多路复用总结

IO多路复用的特性:(监听多个连接)

  • 全程阻塞 wait for data copy data
  • 监听多个文件描述符

4 异步IO

全程无阻塞

实现起来复杂的

658994-20170510144144676-114384592.jpg

最后总结:

阻塞IO,进程一直等待

非阻塞IO,copy data 的过程是阻塞的
IO多路复用,全程阻塞

  • 有阻塞的就是同步IO

    (阻塞IO 、非阻塞IO(copy data),IO多路复用)

  • 没有阻塞的是异步IO

[^1]

[^2]

转载于:https://www.cnblogs.com/Python666/p/6835885.html

你可能感兴趣的文章
java入门
查看>>
Spring 整合 Redis
查看>>
Azure 托管镜像和非托管镜像对比
查看>>
SQLite3初探
查看>>
多线程/多进程/异步IO
查看>>
leetcode 442. 数组中重复的数据 java
查看>>
struts2 文件上传下载注解示例
查看>>
编写一个简单的JAVA WEB Servlet页面
查看>>
JSP:Cookie实现永久登录(书本案例)
查看>>
js window.open 参数设置
查看>>
032. asp.netWeb用户控件之一初识用户控件并为其自定义属性
查看>>
linux--GCC用法
查看>>
Ubuntu下安装MySQL及简单操作
查看>>
OWIN是什么?
查看>>
前端监控
查看>>
centos6.5 mysql忘记登入密码
查看>>
Trusted Execution Technology (TXT) --- 启动控制策略(LCP)篇
查看>>
clipboard.js使用方法
查看>>
绘图库:Matplotlib
查看>>
0906第一次作业
查看>>