﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-不急不徐，持之以恒。-随笔分类-Node.js</title><link>http://www.blogjava.net/linli/category/54789.html</link><description>http://blog.gopersist.com/</description><language>zh-cn</language><lastBuildDate>Tue, 21 Apr 2015 14:41:12 GMT</lastBuildDate><pubDate>Tue, 21 Apr 2015 14:41:12 GMT</pubDate><ttl>60</ttl><item><title>Node.js的异步I/O</title><link>http://www.blogjava.net/linli/archive/2015/04/13/424380.html</link><dc:creator>老林</dc:creator><author>老林</author><pubDate>Mon, 13 Apr 2015 13:42:00 GMT</pubDate><guid>http://www.blogjava.net/linli/archive/2015/04/13/424380.html</guid><wfw:comment>http://www.blogjava.net/linli/comments/424380.html</wfw:comment><comments>http://www.blogjava.net/linli/archive/2015/04/13/424380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/linli/comments/commentRss/424380.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/linli/services/trackbacks/424380.html</trackback:ping><description><![CDATA[<h2>Linux操作系统的I/O模型</h2><p style="margin: 0px 0px 15px; padding: 0px; color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; background-color: #fdfdfd;">JAVA的NIO引入了异步I/O，而Node.js宣称的就是异步编程，I/O自然是异步的。其实操作系统在很早就引入了异步I/O的概念，如下图（摘自Unix网络编程中的图片）：</p><p style="margin: 0px 0px 15px; padding: 0px; color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; background-color: #fdfdfd;"><img src="http://blog.gopersist.com/images/io-node/linux-io-model.jpg" alt="" style="max-width: 100%; vertical-align: middle;" /></p><p style="margin: 0px 0px 15px; padding: 0px; color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; background-color: #fdfdfd;">我对上图的理解有几点：</p><ol style="margin: 0px 0px 15px 30px; padding: 0px; color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; background-color: #fdfdfd;"><li>从IO设备读取数据到用户内存的整个过程都是由系统内核来完成；</li><li>数据总是先被拷贝到内核缓冲区，再由内核缓冲区拷贝到用户内存；</li><li>除了异步I/O，其余4种I/O模型其实都是阻塞的，至少在数据从内核拷贝到用户内存时是阻塞的；</li><li>虽然异步I/O看上去是理想解决方案，但实现上现在用得最多的应该是多路I/O复用，有select、poll、epoll的实现，性能最好的是epoll；</li><li>异步I/O现在被认为有缺陷，仅支持O_DIRECT而无法支持系统缓存。</li></ol><h2>Node.js中的异步I/O</h2><p style="margin: 0px 0px 15px; padding: 0px; color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; background-color: #fdfdfd;">因为内核中的异步I/O有缺陷，现实中的异步I/O通常由用户态的线程池模拟完成，如下图：</p><p style="margin: 0px 0px 15px; padding: 0px; color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; background-color: #fdfdfd;"><img src="http://blog.gopersist.com/images/io-node/node-aio.png" alt="" style="max-width: 100%; vertical-align: middle;" /></p><p style="margin: 0px 0px 15px; padding: 0px; color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; background-color: #fdfdfd;">Node.js中原本使用了libeio异步I/O库，在v0.9.3后改为自己实现的线程池来完成异步I/O。所以在Node.js中，除了用户的Javascript代码是单线程外，所有I/O都是多线程并行执行的。</p><h2>Node.js中的异步I/O调用</h2><p style="margin: 0px 0px 15px; padding: 0px; color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; background-color: #fdfdfd;">Node.js通过事件循环的模式运行，在每一个循环的过程中，通过询问一个或多个观察者来判断是否有事件要处理，而观察者可以有文件I/O观察者、网络I/O观察者等。</p><p style="margin: 0px 0px 15px; padding: 0px; color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; background-color: #fdfdfd;">Node.js中异步I/O调用的大致流程如下：</p><ul style="margin: 0px 0px 15px 30px; padding: 0px; background-color: #fdfdfd;"><li style="color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;"><em>发起I/O调用</em><ol style="margin: 0px 0px 0px 30px; padding: 0px;"><li>用户通过Javascript代码调用Node核心模块，将参数和回调函数传入到核心模块；</li><li>Node核心模块会将传入的参数和回调函数封装成一个请求对象；</li><li>将这个请求对象推入到I/O线程池等待执行；</li><li>Javascript发起的异步调用结束，Javascript线程继续执行后续操作。</li></ol></li><li><em style="color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">执行回调</em><ol style="color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; margin: 0px 0px 0px 30px; padding: 0px;"><li>I/O操作完成后，会将结果储存到请求对象的result属性上，并发出操作完成的通知；</li><li>每次事件循环时会检查是否有完成的I/O操作，如果有就将请求对象加入到I/O观察者队列中，之后当做事件处理；</li></ol><ul><li><font color="#111111" face="Helvetica, Arial, sans-serif"><span style="font-size: 16px; line-height: 24px;"><br /></span></font></li></ul></li><li style="color: #111111; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">处理I/O观察者事件时，会取出之前封装在请求对象中的回调函数，执行这个回调函数，并将result当参数，以完成Javascript回调的目的。<br /><br />微信订阅号：<img src="http://blog.gopersist.com/images/about/weixin.jpg" width="100" height="100" alt="" style="max-width: 100%; vertical-align: middle;" /><br />源文地址：<a href="http://blog.gopersist.com" title="作者博客：http://blog.gopersist.com"><div style="display: inline !important;">http://blog.gopersist.com/2015/03/09/aio/</div></a></li></ul><img src ="http://www.blogjava.net/linli/aggbug/424380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/linli/" target="_blank">老林</a> 2015-04-13 21:42 <a href="http://www.blogjava.net/linli/archive/2015/04/13/424380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>