1回顶部 上一篇:Java I/O API之性能分析 (上) 接下来我们要分析Connection的register()方法。前面我们总是说用Selector注册的连接,其实这是一种简化的说法。实际上,用Selector注册的是一个java.nio.channels.SocketChannel对象,但只针对特定的I/O操作。注册之后,有一个java.nio.channels.SelectionKey被返回。这个选择键可以通过attach()方法关联到任意对象。为了通过键获得连接,这里把Connection对象关联到键。这样,我们就可以从Selector间接地获得一个Connection。
回过头来看ConnectionSelector。select()方法的返回值表示有多少连接已经做好了I/O操作的准备。如果返回值是0,则返回;否则,调用selectedKeys()获得键的集合(Set),从这些键获得以前关联的Connection对象,然后调用其readRequest()或writeResponse()方法,具体调用哪一个方法由连接被注册为读取操作还是写入操作决定。 现在再来看Connection类。Connection类代表着连接,处理所有协议有关的细节。在构造函数中,通过参数传入的SocketChannel被设置成非阻塞模式,这对于服务器来说是很重要的。另外,构造函数还设置了一些默认值,分配了缓冲区requestLineBuffer。由于分配直接缓冲区代价稍高,且这里的每一个连接都用一个新的缓冲区,因此这里使用java.nio.ByteBuffer.allocate()而不是ByteBuffer.allocateDirect()。如果重用缓冲区,直接缓冲区可能具有更高的效率。
完成所有初始化工作且SocketChannel做好了读取准备之后,ConnectionSelector调用了readRequest()方法,利用socketChannel.read(requestLineBuffer)方法把所有可用的数据读入缓冲区。如果不能读取完整的行,则返回发出调用的ConnectionSelector,允许另一个连接进入处理过程;反之,如果成功地读取了整个行,接下来应该做的是象在Httpd中一样解析请求。如果当前的请求合法,程序为请求目标文件创建一个java.nio.Channels.FileChannel,并调用prepareForResponse()方法。
2回顶部 prepareForResponse()方法构造出缓冲区responseLine以及(如果必要的话)应答头或错误信息,并把这些数据写入responseLineBuffer。这个ByteBuffer是一个byte数组的简单的封装器。生成待输出的数据之后,我们还要通知ConnectionSelector:从现在开始不再读取数据,而是要写入数据了。这个通知通过调用选择键的interestedOps(SelectionKey.OP_WRITE)方法完成。为了保证选择器能够迅速认识到连接操作状态的变化,接着还要调用wakeup()方法。接下来ConnectionSelector调用连接的writeResponse()方法。首先,responseLineBuffer被写入到Socket管道。如果缓冲区的内容全部被写入,而且还有被请求的文件需要发送,接着调用前面打开的FileChannel的transferTo()方法。transferTo()方法通常能够高效地把数据从文件传输到管道,但实际的传输效率依赖于底层的操作系统。任何时候,被传输的数据量至多相当于在无阻塞的情况下可写入目标管道的数据量。为安全和确保各个连接之间的公平起见,这里把上限设置成64 KB。 如果所有数据都已经传输完毕,close()执行清理工作。取消Connection的注册是这里的主要任务,具体通过调用键的cancel()方法完成。
这个新的方案性能如何呢?答案是肯定的。从原理上看,一个Acceptor和一个ConnectionSelector足以支持任意数量的打开的连接。因此,新的实现方案在可伸缩性方面占有优势。但是,由于两个线程必须通过同步的queue()方法通信,它们可能互相阻塞对方。解决这个问题有两种途径: ·改进实现队列的方法 与Httpd相比,NIOHttpd的一个缺点是,对于每一个请求,就有一个新的带缓冲的Connection对象被创建。这就导致了垃圾收集器产生的额外的CPU占用,这部分附加代价的具体程度又与VM的类型有关。然而,Sun不厌其烦地强调说,有了Hotspot,短期生存的对象不再成为问题。 五、可伸缩性的定量分析和比较 在可伸缩性方面,NIOHttpd到底比Httpd好多少?下面我们来看看具体的数字。首先要声明的是,这里的数字具有大量的推测成分,一些重要的环境因素,例如线程同步、上下文切换、换页、硬盘速度和缓冲等,都没有考虑到。首先评估处理r个并发的请求需要多少时间,假设被请求的文件大小是s字节,客户端的带宽是b字节/秒。对于Httpd,这个时间显然直接依赖于线程的数量t,因为同一时刻只能处理t个请求。所以Httpd的处理时间可以从公式一得到,其中c是执行请求分析之类操作的开销常量,这个值对于每一个请求来说都是一样的。另外,这里假定从磁盘读取数据的速度总是快于写入Socket的速度,服务器带宽总是大于客户机带宽之和,且CPU未满载。因此,服务器端的带宽、缓冲和硬盘速度等因素都不必在该公式中考虑。
3回顶部 然而,NIOHttpd的处理时间不再依赖于t。对于NIOHttpd,传输时间l在很大程度上依赖于客户端的带宽b、文件大小s以及前面提到的常数c。由此可以得出公式二,从该公式可以得到NIOHttpd的最小传输时间。 图二:公式二
图三:公式三 进一步的分析表明,如果s、b、t和c是常数,r 趋向无穷时d的增长趋向于一个极限,从公式四可以方便地计算出这个极限。 图四:公式四 因此,除了线程的数量和常量性的开销,连接的时长s/b对d具有极端重要的影响。连接持续的时间越长,d值越小,NIOHttpd对比Httpd的优势也就越高。表一显示出,当c=10ms,t=100,s=1mb,b=8kb/s时,NIOHttpd要比Httpd快126倍。如果连接持续了很长一段时间,NIOHttpd表现出巨大的优势。当连接时间较短时,例如在100 Mb的局域网内,如果文件较大,NIOHttpd表现出10%的优势;如果文件较小,优势不明显。
4回顶部 上述计算假定NIOHttpd和Httpd的常量性开销大致相同,且服务器的不同实现方式也没有带来新的开销。如前所述,这个比较是一个理想条件下的比较。然而,对于形成哪一种实现方式占有更多优势这一概念来说,上述比较已经足够了。 结束语: Java新的I/O API能够有效地提高服务器的可伸缩性。与旧的API相比,新的API要复杂一些,需要更深入地了解多线程和同步。然而,一旦你跨越了这些障碍,就会发现新的I/O API是对Java 2平台的必要的、有用的改进。
|
闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧湱鈧懓瀚崳纾嬨亹閹烘垹鍊炲銈嗗坊閸嬫挻娼诲┑瀣拺闂侇偆鍋涢懟顖涙櫠閹绢喗鐓涢悘鐐插⒔閵嗘帡鏌嶈閸撱劎绱為崱娑樼;闁告侗鍘鹃弳锔锯偓鍏夊亾闁告洦鍓涢崢鎼佹倵閸忓浜鹃梺閫炲苯澧寸€规洑鍗冲浠嬵敇濠ф儳浜惧ù锝囩《濡插牊淇婇姘Щ闁绘宀稿娲川婵犲倸顫庨梺绋款儐閹告瓕顣炬繝銏f硾椤戝嫮鎹㈤崱娑欑厽闁规澘鍚€缁ㄥ鏌嶈閸撴岸宕归崹顔炬殾闁哄洨鍠撶弧鈧┑顔斤供閸撴盯顢欓崱娑欌拺閻犳亽鍔屽▍鎰版煙閸戙倖瀚� (0) +1 闂傚倸鍊搁崐鎼佸磹閹间礁纾圭€瑰嫭鍣磋ぐ鎺戠倞鐟滃繘寮抽敃鍌涚厱妞ゎ厽鍨垫禍婵嬫煕濞嗗繒绠抽柍褜鍓欑粻宥夊磿闁秴绠悗锝庡枛鐟欙箓鎮楅敐搴℃灍闁绘挻娲熼弻宥夊煛娴e憡鐏撳┑鐐茬墑閸ㄥ綊婀佺紒缁㈠弮閺€杈┾偓姘炬嫹 (0) +1 闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁炬儳缍婇弻鐔兼⒒閹绢喗顎栭梺绋款儐閸ㄥ潡骞冨Δ鈧埥澶娾枎鐎n剛绐楁俊鐐€愰弲婊堟偂閿熺姴钃熼柨婵嗩槸缁狅綁鏌ㄥ┑鍡橈紞婵☆偄瀚槐鎾存媴閸濆嫷鈧矂鏌涢妸銉у煟鐎殿喖顭锋俊鎼佸煛閸屾矮绨介梻浣呵归張顒傜矙閹达富鏁傞柨鐕傛嫹 (0) +1
闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧湱鈧懓瀚崳纾嬨亹閹烘垹鍊炲銈嗗坊閸嬫挻娼诲┑瀣拺闂侇偆鍋涢懟顖涙櫠閹绢喗鐓涢悘鐐插⒔閵嗘帡鏌嶈閸撱劎绱為崱娑樼;闁告侗鍘鹃弳锔锯偓鍏夊亾闁告洦鍓涢崢鎼佹倵閸忓浜鹃梺閫炲苯澧寸€规洑鍗冲浠嬵敇濠ф儳浜惧ù锝囩《濡插牊淇婇姘Щ闁绘宀稿娲川婵犲倸顫庨梺绋款儐閹告瓕顣炬繝銏f硾椤戝嫮鎹㈤崱娑欑厽闁规澘鍚€缁ㄥ鏌嶈閸撴岸宕归崹顔炬殾闁哄洢鍨归拑鐔兼煏婢跺牆鍔氶柣搴弮濮婅櫣绮旈崱妤€顏存繛鍫熸閺岋箓宕橀鍕亪闂佸搫鐭夌紞浣割嚕椤曗偓瀹曞爼濡烽姀鐘卞闂侀€炲苯澧撮柡灞剧〒閳ь剨缍嗛崑鍛焊椤撱垺鐓冮柦妯侯樈濡叉悂鏌嶇拠鑼фい銏∏归ˇ杈╃磼閵娿儯鍋㈤柡宀€鍠愮粭鐔煎垂椤旂⒈娼庨柣搴ゎ潐濞叉﹢宕曟總鏉嗗洭顢氶埀顒勫蓟閿熺姴鐒垫い鎺戝閸ゅ秹鏌曟径娑氬缂併劌顭峰娲传閸曨剙绐涢梺绋款儑閸嬨倛妫㈤梺缁樺姉閸庛倝宕愰崹顐e弿婵☆垳鍘ф禍楣冩倵濮樼偓瀚�闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾剧懓顪冪€n亝鎹i柣顓炴閵嗘帒顫濋敐鍛婵°倗濮烽崑鐐烘偋閻樻眹鈧線寮撮姀鐘栄囨煕閳╁啨浠︾紒顔瑰墲娣囧﹪鎮欓鍕ㄥ亾閺嶎厼绀夌憸蹇曞垝婵犳艾绠i柣妯烘▕濡粓姊虹粔鍡楀濞堟洟鏌i幘瀛樼闁哄瞼鍠栭弻鍥晝閳ь剟鎮橀柆宥嗙厱闁靛牆鎷嬮崕鏃堟煛鐏炶鈧繂顕i崼鏇炵閹肩补鈧弶妯婇梻鍌欑閹碱偊寮甸鍌滅煓闁硅揪绠戦悡鈥愁熆鐠哄彿鍫ュ几鎼淬劍鐓欓梺顓ㄧ畱閺嬨倝鏌嶇拠鑼缂佽鲸鎹囧畷鎺戭潩椤戣棄浜惧瀣婵ジ鏌$仦璇插姎闁汇倝绠栭弻锝呂熷▎鎯ф闂佽棄鍟伴崰鏍蓟閿濆绫嶉柛灞绢殕鐎氭盯姊烘潪鎵槮缂佸鏁搁幑銏犫攽閸モ晝鐦堥梺绋挎湰绾板秹鎮橀幘缁樷拺闁告繂瀚敍宥夋煕濡亽鍋㈤柍銉︽瀹曟﹢顢欓崲澹洦鐓曢柟鎵虫櫅婵$厧鈹戦鎯у幋婵﹥妞介幃鐑藉级閹稿寒鍞ㄩ梻浣烘嚀閸ゆ牠骞忛敓锟�>>
正在阅读:Java I/O API之性能分析 (下)Java I/O API之性能分析 (下)
2004-12-20 15:18
出处:CSDN
责任编辑:linjixiong