简单聊下IO复用

没图,不分析API

Java中IO API的发展:
Socket -> SocketChannel -> AsynchronousSocketChannel
ServerSocket -> ServerSocketChannel -> AsynchronousServerSocketChannel

同步/阻塞 -> 同步/非阻塞(多路复用) -> 异步

想简单聊下多路复用。多路复用需要配合Reactor模式,前者解决技术上的问题,后者解决软件工程的问题。

技术上的问题,是将IO操作中等待和非等待的部分分开处理。我们都知道IO操作分为两个部分:
1、等待数据就绪
2、处理数据

众所周知的几种IO模型(阻塞、非阻塞、多路复用、信号驱动、异步)就是区别于这两个阶段,当需要处理很多连接的时候(高并发的情况),容易想到的是使用多线程技术,比如最简单的One-connection-Per-thread模式,但是因为等待数据不可避免,造成的结果是线程不停的休眠-唤醒的切换,导致CPU不堪重负。

IO复用的目的:将这两个阶段分开处理,让一个线程(而且是内核级别的线程)来处理所有的等待,一旦有相应的IO事件发生就通知继续完成IO操作,虽然仍然有阻塞和等待,但是等待总是发生在一个线程,这时使用多线程可以保证其他线程一旦唤醒就是处理数据,当然这需要非阻塞IO API的支持(比如非阻塞套接字)。Linux2.6之前的select,poll以及之后的epoll都是IO复用技术的实现。selectpoll基本一致,epoll是对它们的改进版本。但总的来说它们都还不是真正的异步IO,因为它们在IO读写的时候仍然是阻塞的、同步的(完成一件事后才能做另外一件事)。异步IO是指“处理数据”这一阶段也是非阻塞的。Windows上的IOCP(完成端口)才是真正的AIO,理论上它比Linux的epoll更先进。

至于select、poll和epoll的区别,推荐这篇文章:http://www.cnblogs.com/Anker/p/3265058.html。简单来说:select,poll无脑的轮询,忽略了高并发下,轮询本身成了瓶颈,而epoll使用回调实现了轮询真正需要处理的连接。

Reactor模式是为了我们更简单的使用IO复用技术。它是一种并发IO模式,其他的模式还有多进程,多线程等。Reactor本身也有很多变种,比如thread per request,worker thread,thread pool,multiple reactors...网上这方面的资料很多。虽然网上关于reactor和多线程模孰优孰劣还有争论(Reactor最明显的一个缺点是无法充分利用多核的优势),但是大部分高并发的框架或组建都是基于reactor的,比如MINA,Netty,再比如Redis,Nginx(有多个工作进程来充分利用多核的优势)。关于Java中的IO复用可以看Doug Lea大神的Scalable IO in Java(http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf)。

至于JDK1.7中出现的Asynchronous I/O,只要是运行Linux上肯定无外乎epoll,那是不是可以说本质上仍然不是真正的异步IO呢?个人觉得异步这个概念是有粒度的,不可能做到完全的异步。JDK1.7中的AIO从编程的角度对程序员来说确是异步的,我们不用像在多路复用中那样自己去select了,我们需要做的就是在completion handlers中处理业务逻辑。

另外提一点:操作系统底层的IO操作都是异步的——IO中断,只不过同步更符合正常人的思维,更易于理解。

最后关于异步IO还想补充一点,虽然异步IO的第二阶段也是非阻塞的,但是仍然有优化空间。就是在数据从内核copy到用户空间这个过程,Netty就使用了Zero-Copy技术来优化这个步骤(http://my.oschina.net/plucury/blog/192577),另外还有MMAP。

欢迎斧正!

时间: 2024-08-10 02:10:41

简单聊下IO复用的相关文章

简单聊下Unicode和UTF-8

今晚听同事分享提到这个,简单总结下. ## Unicode字符集 Unicode的出现是因为ASCII等其他编码码不够用了,比如ASCII是英语为母语的人发明的,只要一个字节8位就能够表示26个英文字母了,但是当跨区域进行信息交流的时候,尤其是Internet的出现,除了“A”,“B”,“C",还有“你”,“我”,“他”需要表示,一个字节8位显然不够用,够因此Unicode就被发明出来,Unicode的最大码位0x10FFFF,有21位.中文对应的Unicode编码见http://www.chi

《深入理解计算机系统》Tiny服务器4——epoll类型IO复用版Tiny

前几篇博客分别讲了基于多进程.select类型的IO复用.poll类型的IO复用以及多线程版本的Tiny服务器模型,并给出了主要的代码.至于剩下的epoll类型的IO复用版,本来打算草草带过,毕竟和其他两种IO复用模型差不太多.但今天在看Michael Kerrisk的<Linux/UNIX系统编程手册>时,看到了一章专门用来讲解epoll函数,及其IO复用模型.于是,自己也就动手把Tiny改版了一下.感兴趣的同学可以参考上述手册的下册1113页,有对于epoll比较详细的讲解. 前边针对IO

IO复用

IO复用简单介绍 IO复用使得程序能同一时候监听多个文件描写叙述符.这对提高程序的性能至关重要.通常.网络程序在下列情况下须要使用IO复用技术: client程序要同一时候处理多个socket. client程序要同一时候处理用户输入和网络连接. TCPserver同一时候处理监听socket和连接socket. server要同一时候处理TCP请求和UDP请求. 须要指出的是.IO复用尽管能同一时候监听多个文件描写叙述符,但它本身是堵塞的.而且当多个文件描写叙述符同一时候就绪时,假设不採取额外

Libevent的IO复用技术和定时事件原理

Libevent 是一个用C语言编写的.轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大:源代码相当精炼.易读:跨平台,支持 Windows. Linux. *BSD 和 Mac Os:支持多种 I/O 多路复用技术, epoll. poll. dev/poll. select 和 kqueue 等:支持 I/O,定时器和信号等事件:注册事件优先级. 1 Libevent中的epoll Libevent重

Linux中的IO复用接口简介(文件监视?)

I/O复用是Linux中的I/O模型之一.所谓I/O复用,指的是进程预先告诉内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程进行处理,从而不会在单个I/O上导致阻塞. 在Linux中,提供了select.poll.epoll三类接口来实现I/O复用. select函数接口 select中主要就是一个select函数,用于监听指定事件的发生,原型如下: 12345 #include<sys/select.h>#include<sys/time.h>int sele

[Z] linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO

原文链接:http://blog.csdn.net/colzer/article/details/8169075 IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file descriptor(fd,文件描述符).而对一个socket的读写也会有相应的描述符,称为socketfd(socket描述符).描述符就是一个数字,指向内核中一个结构体(文件路径,数据

linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)

IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file descriptor(fd,文件描述符).而对一个socket的读写也会有相应的描述符,称为socketfd(socket描述符).描述符就是一个数字,指向内核中一个结构体(文件路径,数据区,等一些属性).那么我们的应用程序对文件的读写就通过对描述符的读写完成. linux将内存分为内核区,用户区.l

IO复用、多进程和多线程三种并发编程模型

I/O复用模型 I/O复用原理:让应用程序可以同时对多个I/O端口进行监控以判断其上的操作是否可以进行,达到时间复用的目的.在书上看到一个例子来解释I/O的原理,我觉得很形象,如果用监控来自10根不同地方的水管(I/O端口)是否有水流到达(即是否可读),那么需要10个人(即10个线程或10处代码)来做这件事.如果利用某种技术(比如摄像头)把这10根水管的状态情况统一传达到某一点,那么就只需要1个人在那个点进行监控就行了,而类似与select或epoll这样的多路I/O复用机制就好比是摄像头的功能

IO复用(Reactor模式和Preactor模式)——用epoll来提高服务器并发能力

上篇线程/进程并发服务器中提到,提高服务器性能在IO层需要关注两个地方,一个是文件描述符处理,一个是线程调度. IO复用是什么?IO即Input/Output,在网络编程中,文件描述符就是一种IO操作. 为什么要IO复用? 1.网络编程中非常多函数是阻塞的,如connect,利用IO复用可以以非阻塞形式执行代码. 2.之前提到listen维护两个队列,完成握手的队列可能有多个就绪的描述符,IO复用可以批处理描述符. 3.有时候可能要同时处理TCP和UDP,同时监听多个端口,同时处理读写和连接等.