linux下的io模型

1、用户态和内核态

因为操作系统的资源是有限的,如果访问资源的操作过多,必然会消耗过多的资源,而且如果不对这些操作加以区分,很可能造成资源访问的冲突。所以,为了减少有限资源的访问和使用冲突,Unix/Linux的设计哲学之一就是:对不同的操作赋予不同的执行等级,就是所谓特权的概念。简单说就是有多大能力做多大的事,与系统相关的一些特别关键的操作必须由最高特权的程序来完成。Intel的X86架构的CPU提供了0到3四个特权级,数字越小,特权越高,Linux操作系统中主要采用了0和3两个特权级,分别对应的就是内核态和用户态。运行于用户态的进程可以执行的操作和访问的资源都会受到极大的限制,而运行在内核态的进程则可以执行任何操作并且在资源的使用上没有限制。很多程序开始时运行于用户态,但在执行的过程中,一些操作需要在内核权限下才能执行,这就涉及到一个从用户态切换到内核态的过程

用户态和内核态的转换

a、系统调用

系统调用的本质其实也是中断,相对于外围设备的硬中断,这种中断称为软中断

b、异常

当CPU正在执行运行在用户态的程序时,突然发生某些预先不可知的异常事件,这个时候就会触发从当前用户态执行的进程转向内核态执行相关的异常事件,典型的如缺页异常。

c、外围设备的中断

当外围设备完成用户的请求操作后,会像CPU发出中断信号,此时,CPU就会暂停执行下一条即将要执行的指令,转而去执行中断信号对应的处理程序,如果先前执行的指令是在用户态下,则自然就发生从用户态到内核态的转换

总结:

内核态可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。

2、同步和异步的区别

同步io需要主动读写数据,在读写过程中会阻塞,异步io只需要读写完成的通知,读写操作由内核态完成

3、关于异步阻塞和异步非阻塞

异步阻塞,用户进程(线程)发起读写操作,在原地等待内核态返回读写完成的结果。此时阻塞整个进程
异步非阻塞,用户进程发起读写操作后,不在原地的等待内核态完成读写操作的结果。可以先去干点别的事

4、同步的几种io模型

以read为例

1、同步阻塞

1、进程发起read,进行recvfrom系统调用;

2、内核态准备数据

3、同时进程阻塞

4、阻塞直到数据从内核态copy到用户态,内核返回结果,进程解除阻塞。

总结:准备数据和数据copy两个阶段都阻塞。

image

2、同步非阻塞

1、进程发起read操作,内核数据没有准备好,立刻返回一个error.

2、用户进程收到error,知道数据没有准备好,于是再次发起read操作,直到数据准备好。

3、用户进程收到数据准备好的信号,发送system call,copy数据,此时进程开始阻塞

4、数据copy完成,返回给用户进程解除阻塞。

总结:数据准备阶段,用户进程不断询问内核数据准备好了没,数据copy阶段进程阻塞

image

3、io多路复用

1、用户进程调用select,进程阻塞,同时内核会监听所有select负责的socket.

2、当任何一个socket的数据准备好,select就会返回。

3、用户进程调用read操作,将数据从内核copy到用户进程。

总结:I/O 多路复用的特点是通过一种机制一个进程能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select()函数就可以返回

如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用多线程 + 阻塞 IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。
image

select、poll、epoll的区别:

select 是不断轮询去监听的socket,socket个数有限制,一般为1024个;

poll还是采用轮询方式去监听,只不过没有个数限制。

epoll并不用采用轮询方式去监听,而是当socket有变化时通过回调方式主动告知用户进程。

select支持多平台,epoll只支持linux平台。

select实现ftp
import select
import socket

server = socket.socket()
server.bind(('127.0.0.1', 9991))
server.listen(10)
server.setblocking(False)

r_list = [server, ]
w_list = []
w_data = {}

while True:
    rl, wl, xl = select.select(r_list, w_list, [], 0.5)
    print(wl)
    for sock in rl:
        if sock == server:
                conn, addr = server.accept()
                r_list.append(conn)
        else:
            try:
                data = sock.recv(1024).decode()
                if not data:
                    sock.close()
                    r_list.remove(sock)
                    continue
                w_list.append(sock)
                w_data[sock] = data.upper().encode()
    
            except Exception as e:
                print(e)
                sock.close()
                r_list.remove(sock)

selectors实现ftp

import selectors
import socket


def accept(obj, mask):
    conn,addr = obj.accept()
    sel.register(conn, selectors.EVENT_READ, read)
    

def read(obj,mask):
  
    try:
        data = obj.recv(1024).decode()
        if not data:
            sel.unregister(obj)
            obj.close()
            return
        print(data)
        obj.send(data.upper().encode())
    except Exception as e:
        print(e)
        obj.close()
        sel.unregister(obj)
    

server = socket.socket()
server.bind(('127.0.0.1', 9990))
server.listen(10)
server.setblocking(False)
sel = selectors.DefaultSelector()
sel.register(server, selectors.EVENT_READ, accept)
while True:
    events = sel.select()
    for obj, mask in events:
        callback = obj.data
        callback(obj.fileobj, mask)

大量参考:
http://www.cnblogs.com/zingp/p/6863170.html
https://www.cnblogs.com/bakari/p/5520860.html

转载于:https://www.cnblogs.com/Jason-lin/p/8723743.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux内核的IO模型主要包括阻塞IO、非阻塞IO、多路复用IO和异步IO。下面我将逐个介绍这些模型的特点。 1. 阻塞IO(Blocking IO):当应用程序发起一个IO操作后,内核会一直阻塞等待,直到IO操作完成才返回结果给应用程序。在这期间,应用程序是被阻塞的,无法进行其他操作。阻塞IO模型适用于对实时性要求不高的场景,简单易用,但会导致资源浪费。 2. 非阻塞IO(Non-Blocking IO):当应用程序发起一个IO操作后,内核会立即返回一个结果给应用程序,无论IO操作是否完成。如果IO操作还未完成,应用程序可以继续做其他事情,而不需要一直等待。应用程序可以通过轮询来检查IO操作的状态,直到操作完成。非阻塞IO模型可以提高系统的并发性能,但需要应用程序自己处理轮询逻辑。 3. 多路复用IO(Multiplexing IO):多路复用IO模型通过一个系统调用(如select、poll、epoll等)来同时监听多个IO事件,当有任意一个IO事件就绪时,内核会通知应用程序进行处理。这种模型避免了阻塞和轮询的问题,可以同时处理多个IO操作,提高系统的并发性能。 4. 异步IO(Asynchronous IO):异步IO模型中,应用程序发起一个IO操作后,可以立即返回继续执行其他操作,而不需要等待IO操作完成。当IO操作完成后,内核会通知应用程序,并返回结果。异步IO模型通过回调函数来处理IO完成的通知,相比于其他模型,可以更高效地处理大量的IO操作。 这些IO模型在不同的场景下有各自的优劣,选择合适的IO模型可以提高系统的性能和响应能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值