[size=large][b]异步I/O处理过程[/b][/size]
[img]http://dl.iteye.com/upload/attachment/0078/0527/95fe9a76-691b-36ee-931c-fe2b39923430.jpg[/img]
[b]异步I/O处理的优点[/b]
I/O密集型计算(进程所执行的I/O操作比执行的处理操作更多)的任务中,使用异步I/O的方式,可以提高CPU对应用程序处理的吞吐率,应用程序无需进行I/O阻塞。保证在I/O处理时,仍能进行应用程序的处理
[b]异步I/O的缺点[/b]
如果程序的I/O操作频繁并且短暂,则I/O线程切换代价较大,并且异步I/O库处理有一定的开销(磁盘磁头的寻址切换等),异步I/O对程序的写法有一定的门槛。
[b]异步I/O的应用场景[/b]
NodeJS的单进程,单线程模型。为了能同时处理更多的请求,I/O操作,必需使用异步处理的方式,NodeJS采用的是libeio的实现方式。
[b]异步I/O的实现[/b]
[size=medium][b]glibc:[/b][/size]
在文件目录下新建file.txt文件,file.txt内容:hello world!
compile: gcc aio_demo.c -o aio_demo.o -lrt
run: ./aio_demo.o
result:
caller thread
callback
data: hello world!
[size=medium][b]kernel native aio:[/b][/size]
待完善
[size=medium][b]libeio:[/b][/size]
libeio的源码下载:https://github.com/scunningham/libeio
libeio的编译及运行过程:
运行结果:
[img]http://dl.iteye.com/upload/attachment/0078/1024/0af6b812-2597-396f-954b-b58658ec20db.jpg[/img]
具体的libeio源码及流程分析可以查看大牛已经做的文档:
[url=http://cnodejs.org/topic/4f2c0391ab3b872077002f00]NodeJS代码阅读笔记之libeio[/url]
[url=http://blog.youkuaiyun.com/lanyan822/article/details/7644745]libeio异步I/O初探[/url]
[size=medium][b]Java:[/b][/size]
Server端:
Client:
参考文章:
1.[url=http://www.ibm.com/developerworks/cn/linux/l-async/]使用异步I/O大大提高应用程序的性能[/url]
2.[url=http://cnodejs.org/topic/4f16442ccae1f4aa270010a7]Linux AIO(异步IO)那些事儿[/url]
3.[url=http://cnodejs.org/topic/4f2c0391ab3b872077002f00]NodeJS代码阅读笔记之libeio[/url]
[img]http://dl.iteye.com/upload/attachment/0078/0527/95fe9a76-691b-36ee-931c-fe2b39923430.jpg[/img]
[b]异步I/O处理的优点[/b]
I/O密集型计算(进程所执行的I/O操作比执行的处理操作更多)的任务中,使用异步I/O的方式,可以提高CPU对应用程序处理的吞吐率,应用程序无需进行I/O阻塞。保证在I/O处理时,仍能进行应用程序的处理
[b]异步I/O的缺点[/b]
如果程序的I/O操作频繁并且短暂,则I/O线程切换代价较大,并且异步I/O库处理有一定的开销(磁盘磁头的寻址切换等),异步I/O对程序的写法有一定的门槛。
[b]异步I/O的应用场景[/b]
NodeJS的单进程,单线程模型。为了能同时处理更多的请求,I/O操作,必需使用异步处理的方式,NodeJS采用的是libeio的实现方式。
[b]异步I/O的实现[/b]
[size=medium][b]glibc:[/b][/size]
在文件目录下新建file.txt文件,file.txt内容:hello world!
#include <aio.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char bufferAO[8192] __attribute__((aligned(4096)));
void aio_completion_handler(int signo, siginfo_t *info, void *context)
{
int ret;
write(1, "callback\n", 9);
struct aiocb *req;
// Ensure it's our signal
if (info->si_signo == SIGIO) {
req = (struct aiocb *)info->si_value.sival_ptr;
printf("data: %s\n" ,req->aio_buf);
// Did the request complete?
if (aio_error( req ) == 0) {
// Request completed successfully, get the return status
ret = aio_return( req );
}
}
return;
}
int main()
{
int fd, ret;
struct sigaction sig_act;
struct aiocb my_aiocb;
fd = open("file.txt", O_RDONLY);
if(fd < 0){
perror("open fail");
}
// Set up the signal handler
sigemptyset(&sig_act.sa_mask);
sig_act.sa_flags = SA_SIGINFO;
sig_act.sa_sigaction = aio_completion_handler;
// Set up the AIO request
bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
my_aiocb.aio_fildes = fd;
my_aiocb.aio_buf = malloc(sizeof(bufferAO)+1);
my_aiocb.aio_nbytes = sizeof(bufferAO);
my_aiocb.aio_offset = 0;
// Link the AIO request with the Signal Handler
my_aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
my_aiocb.aio_sigevent.sigev_signo = SIGIO;
my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;
// Map the Signal to the Signal Handler
ret = sigaction( SIGIO, &sig_act, NULL );
ret = aio_read(&my_aiocb);
if (ret < 0) {
perror("error info");
}
write(1, "caller thread\n", 14);
sleep(5);
}
compile: gcc aio_demo.c -o aio_demo.o -lrt
run: ./aio_demo.o
result:
caller thread
callback
data: hello world!
[size=medium][b]kernel native aio:[/b][/size]
待完善
[size=medium][b]libeio:[/b][/size]
libeio的源码下载:https://github.com/scunningham/libeio
libeio的编译及运行过程:
./autogen.sh
./configure
make
sudo make install
export LD_LIBRARY_PATH=".libs;$LD_LIBRARY_PATH"
#此时可以编译运行demo.c了
gcc demo.c -o demo -leio
./demo
运行结果:
[img]http://dl.iteye.com/upload/attachment/0078/1024/0af6b812-2597-396f-954b-b58658ec20db.jpg[/img]
具体的libeio源码及流程分析可以查看大牛已经做的文档:
[url=http://cnodejs.org/topic/4f2c0391ab3b872077002f00]NodeJS代码阅读笔记之libeio[/url]
[url=http://blog.youkuaiyun.com/lanyan822/article/details/7644745]libeio异步I/O初探[/url]
[size=medium][b]Java:[/b][/size]
Server端:
package org.operamasks.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Calendar;
import java.util.Iterator;
public class TestServer {
public static void main(String[] args) {
new Thread(new EchoServer(1982)).start();
}
}
class EchoServer implements Runnable {
//要监听的端口号
private int port;
//生成一个信号监视器
private Selector s;
//读缓冲区
private ByteBuffer r_bBuf = ByteBuffer.allocate(1024);
private ByteBuffer w_bBuf;
public EchoServer(int port) {
this.port = port;
try {
s = Selector.open();
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
try {
//生成一个ServerScoket通道的实例对象,用于侦听可能发生的IO事件
ServerSocketChannel ssc = ServerSocketChannel.open();
//将该通道设置为异步方式
ssc.configureBlocking(false);
//绑定到一个指定的端口
ssc.socket().bind(new InetSocketAddress(port));
//注册特定类型的事件到信号监视器上
ssc.register(s, SelectionKey.OP_ACCEPT);
System.out.println("The server has been launched...");
while(true) {
//将会阻塞执行,直到有事件发生
s.select();
Iterator it = s.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey key = it.next();
//key定义了四种不同形式的操作
switch(key.readyOps()) {
case SelectionKey.OP_ACCEPT :
dealwithAccept(key);
break;
case SelectionKey.OP_CONNECT :
break;
case SelectionKey.OP_READ :
dealwithRead(key);
break;
case SelectionKey.OP_WRITE :
break;
}
//处理结束后移除当前事件,以免重复处理
it.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//处理接收连接的事件
private void dealwithAccept(SelectionKey key) {
try {
System.out.println("新的客户端请求连接...");
ServerSocketChannel server = (ServerSocketChannel)key.channel();
SocketChannel sc = server.accept();
sc.configureBlocking(false);
//注册读事件
sc.register(s, SelectionKey.OP_READ);
System.out.println("客户端连接成功...");
} catch (IOException e) {
e.printStackTrace();
}
}
//处理客户端发来的消息,处理读事件
private void dealwithRead(SelectionKey key) {
try {
SocketChannel sc = (SocketChannel)key.channel();
System.out.println("读入数据");
r_bBuf.clear();
//将字节序列从此通道中读入给定的缓冲区r_bBuf
sc.read(r_bBuf);
r_bBuf.flip();
String msg = Charset.forName("UTF-8").decode(r_bBuf).toString();
if(msg.equalsIgnoreCase("time")) {
w_bBuf = ByteBuffer.wrap(getCurrentTime().getBytes("UTF-8"));
sc.write(w_bBuf);
w_bBuf.clear();
} else if(msg.equalsIgnoreCase("bye")) {
sc.write(ByteBuffer.wrap("已经与服务器断开连接".getBytes("UTF-8")));
sc.socket().close();
} else {
sc.write(ByteBuffer.wrap(msg.getBytes("UTF-8")));
}
System.out.println(msg);
System.out.println("处理完毕...");
r_bBuf.clear();
try {
Thread.currentThread();
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String getCurrentTime() {
Calendar date = Calendar.getInstance();
String time = "服务器当前时间:" +
date.get(Calendar.YEAR) + "-" +
date.get(Calendar.MONTH)+1 + "-" +
date.get(Calendar.DATE) + " " +
date.get(Calendar.HOUR) + ":" +
date.get(Calendar.MINUTE) + ":" +
date.get(Calendar.SECOND);
return time;
}
}
Client:
package org.operamasks.nio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
public class TestClient {
public static void main(String[] args) {
new MiniClient("localhost", 1982);
}
}
class MiniClient {
private SocketChannel sc;
private ByteBuffer w_bBuf;
private ByteBuffer r_bBuf = ByteBuffer.allocate(1024);
public MiniClient(String host, int port) {
try {
InetSocketAddress remote = new InetSocketAddress(host, port);
sc = SocketChannel.open();
sc.connect(remote);
if(sc.finishConnect()) {
System.out.println("已经与服务器成功建立连接...");
}
while(true) {
if(!sc.socket().isConnected()) {
System.out.println("已经与服务器失去了连接...");
return ;
}
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine();
System.out.println("读入一行数据,开始发送...");
w_bBuf = ByteBuffer.wrap(str.getBytes("UTF-8"));
//将缓冲区中数据写入通道
sc.write(w_bBuf);
System.out.println("数据发送成功...");
w_bBuf.clear();
System.out.println("接收服务器端响应消息...");
try {
Thread.currentThread();
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
r_bBuf.clear();
//将字节序列从此通道中读入给定的缓冲区r_bBuf
sc.read(r_bBuf);
r_bBuf.flip();
String msg = Charset.forName("UTF-8").decode(r_bBuf).toString();
System.out.println(msg);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
参考文章:
1.[url=http://www.ibm.com/developerworks/cn/linux/l-async/]使用异步I/O大大提高应用程序的性能[/url]
2.[url=http://cnodejs.org/topic/4f16442ccae1f4aa270010a7]Linux AIO(异步IO)那些事儿[/url]
3.[url=http://cnodejs.org/topic/4f2c0391ab3b872077002f00]NodeJS代码阅读笔记之libeio[/url]