IO多路复用

 一.IO多路复用

前面用协程实现IO阻塞自动切换,‘如何去实现事件驱动的情况下IO的自动阻塞的的切换,这个学名叫IO多路复用。

比如socketsew64hmay'y'yver,多个客户端连接,单线程下实现并发效果,这就叫多路复用.

同步io和异步IO,阻塞IO和非阻塞IO的区别?

二.IO模型的前戏准备

  1.用户空间与内核空间

    操作系统的核心是内核,独立于普通应用程序,可以访问受保护的内存空间也有访问底层硬件的权限

    为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。

    各个进程的使用,称为用户空间。

  2.进程切换

    为了控制进程的执行,内核必须有能力挂起正在CPU运行的程序,并恢复以前挂起的某个进程。进程切换由操作系统完成,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关.

    把进程的pbc移入相应的队列,选择另一个进程执行,并更新pbc。

  3.进程的阻塞

    正在执行的进程,由于期待的某些事件未发生,入请求系统资源失败,等待某种操作的完成,新数据尚未到达或无新工作等。则由系统自动执行阻塞,使自己由运行状态变为阻塞状态。进程阻塞是进程自身的一种主动行为,因此只有处于运行状态的进程(获得cpu),才可能将其转换为阻塞状态。当进程进入阻塞状态,是不占用cup资源的。

  4.文件描述符fd

    文件描述符,是一个用于表述指向文件的引用的抽象化概念。

    文件描述符在形式上是一个非负整数,实际上,它是一个索引值。指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有的文件或者创建一个新文件时。内核向进程返回一个文件描述符。

  5.缓存I/O

  缓存IO又称标准I/O,大多数文件系统的默认I/O。在Linux的缓存I/O机制中,操作系统会将I/O的数据缓存在文件系统的页缓存中,即,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间,用户空间没法直接访问内核空间,内核态到用户态的数据拷贝。

  缓存I/O的缺点:

  数据在传输过程中需要在应用程序地址空间和内核空间进行多次数据拷贝操作。这些数据拷贝需要大量的cpu开销。

I/O的分类:

同步(synchronous)io和异步(asynchronous)IO,阻塞(blocking)IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?

  • blocking IO
  • nonblocking IO
  • IO multiplexing
  • signal driven IO
  • asynchronous IO

  对于一个network IO,它会涉及两个系统对象,一个是调用这个IO的进程(process),另一个就是系统内核(kernel).

  当一个read操作发生时,它会经历两个阶段:

  1. 等待数据准备
  2. 将数据从内核拷贝到进程中

blocking  IO(阻塞IO)                                              

  两个部分均在阻塞状态

nonblocking IO(非阻塞 IO)                                                                          


  等待数据时是非阻塞状态,相当于不断询问数据是否准备就绪。

   第一个阶段是非阻塞状态,另一个阶段是阻塞阶段。

                                        I/O multiplexing model(I/O 多路复用 )                                

  IO多路复用,实际就是blocking,并且比blocking更糟糕,但是可以同时监听多个用户。

  有select,poll,epoll

                                    Asynchronous I/O model   (异步 I/O)                                          

   全程都是非阻塞状态。是一个最高效的I/O。   

           IO多路复用的应用           

select,poll,epoll的区别

poll在select的基础上不限同时监听的socket

epoll在poll的基础上可以知道是那一个socket

实际应用

import socket,select

sk1=socket.socket()
sk1.bind(('127.0.0.1',8081))
sk1.listen(3)
inp=[sk1,]
while 1:
    inputs,outputs,errors=select.select(inp,[],[],)
    
    for obj in inputs:
        if obj==sk:
            conn,addr=sk.accept()
            print(conn)
            inp.append(conn)
        else:
            data=obj.recv(1024)
            print(data.decode('utf8'))
            obj.sendall(data)
原文地址:https://www.cnblogs.com/gjx1212/p/12288872.html