进程(六)----IO模型简介

了解IO 前需要了解这几个概念

  1. 用户空间和内核空间
  2. 进程切换
  3. 进程阻塞
  4. 文件描述
  5. 缓存I/O

这里就不做解释了,大家自行百度

Stevens在文章中一共比较了五种IO Model:
    * blocking IO
    * nonblocking IO
    * IO multiplexing
    * signal driven IO
    * asynchronous IO
    由signal driven IO在实际中并不常用,所以主要介绍其余四种IO Model。

  • 阻塞IO

  当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据----等待。而在用户进程这边,整个进程会被阻塞。当kernel数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态便运行起来。
    阻塞 IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被阻塞了。

import  socket
sk  =socket.socket(socket.AF_INET,socket.SOCK_STREAM)

sk.bind(("127。0.0.1",8000))

sk.listen(5)
while 1:

    conn,addr=sk.accept() #阻塞在这里,需要等待请求
    while 1:

        conn.recv(1024)
        conn.send("hello ".encode("utf-8"))

 

 

  • 非阻塞IO

当用户进程发出read操作时,虽然kernel中的数据还没有准备好,但是它并不会锁住用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。
    所以,在非阻塞式IO中,用户进程其实是需要不断的主动询问kernel数据准备好了没有。

import  socket,time
sk  =socket.socket(socket.AF_INET,socket.SOCK_STREAM)

sk.bind(("127。0.0.1",8000))

sk.listen(5)
sk.setblocking(False) #设置非阻塞
while 1:
    try:
        print("do0")
        conn,addr=sk.accept()#没有请求不需要等待,直接退出到except,这里会反复监听是否有请求过来
        print("do1")
        conn.recv(1024)
        print("do2")
        conn.send("hello ".encode("utf-8"))
        conn.close()
    except Exception as e:
        print("非阻塞------",e)
        time.sleep(4)
  • IO多路复用

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。

虽然select性能不及多线程IO,但是可以投同时监听多个对象。

import socket
import select

sk1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk1.bind(('127.0.0.1',8000))
sk1.listen(5)
sk1.setblocking(0)

inputs = [sk1,]

while True:
    readable_list, writeable_list, error_list = select.select(inputs, [], inputs, 1)
    for r in readable_list:
        # 当客户端第一次连接服务端时
        if sk1 == r:
            print('accept')
            request, address = r.accept()
            request.setblocking(0)
            inputs.append(request)
        # 当客户端连接上服务端之后,再次发送数据时
        else:
            received = r.recv(1024)
            # 当正常接收客户端发送的数据时
            if received:
                print('received data:', received)
            # 当客户端关闭程序时
            else:
                inputs.remove(r)

sk1.close()
  • 异步IO

  用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

今天就讲到这里,下一篇给大家写一个FTP上传下载功能

猜你喜欢

转载自blog.csdn.net/Lzs1998/article/details/87873312