Linux下的IO模型介绍

2012年12月15日 | 分类: 操作系统, 编程技术, 网络性能 | 标签:

对于高性能web服务器来说,选择一个合适的io模型至关重要,

IO是什么?
在linux中,一切都是文件,IO操作是指对一个文件描述符的读写操作,一般分为两个阶段,第一个是等待io就绪,第二个是数据在内核空间和用户空间之间的移动。拿read为例子,当用户空间针对一个fd发给read请求时,内核收到通知,内核从物理层得到数据包,数据传到tcpip层,内核解析包头,然后内核将数据包缓存到fd的读缓冲区中,此时还是内核中的操作,当fd的缓冲区内容超过应用程序要读的阀值时(read会设置一个大小),此时该fd的状态就是可读,应用程序此时可以将数据从fd的内核缓冲区拷贝到应用程序中。

目前linux下有5种IO模型:

  • 阻塞型 IO(blocking I/O)
  • 非阻塞性IO(nonblocking I/O)
  • IO多路复用(I/O multiplexing)
  • 信号驱动IO(signal driven I/O)
  • 异步IO(asynchronous I/O)

那么它们的区别在哪里呢?

阻塞和非阻塞的区别:
调用读写的用户进程是否被block住,而不能做其它事情
同步和异步的区别是:
数据是由用户程序做的读写,还是完全由内核完成,而只是通知一下用户程序,
看谁主动把数据拷贝到用户态这样同步和异步的概念就非常明显了。
以上的五种IO模型,前面四种都是同步的,只有第五种IO模型才是异步的IO。

常见的select或者poll,epoll,都是同步io调用,因为最终数据还是要应用程序负责读写到用户态,进行此调用时的用户进程也处于阻塞状态,直到超时。对于poll操作来说,当它执行的时候应用是需要阻塞的,poll在系统调用的时候,需要扫描每一个fd,此时就需要把fd设置成非阻塞的,因为不能让扫描的时候陷入阻塞。在扫描过程中,如果发现有fd可用,此时用户态返回可用的fd列表,等待进一步的io读写操作,因为这时候是应用程序操作内核态数据,因此是poll是同步io。那此时read的操作是阻塞还是非阻塞呢?这时候要看此时fd的属性,可以通过fcntl操作设置。不管过此时fd是阻塞还是非阻塞,都没有任何区别,因为之前的poll,就是知道有数据准备好了才返回的,也就是说内核缓冲区已经有了数据,此时进行read,是肯定能够将数据拷贝到用户进程缓冲区的。当然一般也没有必要在操作时再去设置fd成阻塞。

最后借用一个例子来说明这几种io的区别:
有A,B,C,D,E四个人在钓鱼:
A用的是最老式的鱼竿,所以呢,得一直守着,等到鱼上钩了再拉杆;
B的鱼竿有个功能,能够显示是否有鱼上钩,所以呢,B就和旁边的MM聊天,隔会再看看有没有鱼上钩,有的话就迅速拉杆;
C用的鱼竿和B差不多,但他想了一个好办法,就是同时放好几根鱼竿,然后守在旁边,一旦有显示说鱼上钩了,它就将对应的鱼竿拉起来;
D呢和C差不多,只不过没有守在旁边,可以去忙其它的事情,一旦收到短信就去把鱼钩拉起来。
E是个有钱人,干脆雇了一个人帮他钓鱼,一旦那个人把鱼钓上来了,就给D发个短信。
请自己对号入座

本文的评论功能被关闭了.