时间:2016-10-29来源:本站原创作者:佚名
综述

这篇文章探讨并比较两种用于TCP服务器的高性能设计模式。除了介绍现有的解决方案,还提出了一种更具伸缩性,只需要维护一份代码并且跨平台的解决方案(含代码示例),以及其在不同平台上的微调。此文还比较了java、c#、c++对各自现有以及提到的解决方案的实现性能。

系统I/O可分为阻塞型,非阻塞同步型以及非阻塞异步型[1、2]。阻塞型I/O意味着控制权只到调用操作结束了才会回到调用者手里。结果调用者被阻塞了,这段时间了做不了任何其它事情。更郁闷的是,在等待IO结果的时间里,调用者所在线程此时无法腾出手来去响应其它的请求,这真是太浪费资源了。拿rad()操作来说吧,调用此函数的代码会一直僵在此处直至它所读的sockt缓存中有数据到来。

相比之下,非阻塞同步是会立即返回控制权给调用者的。调用者不需要等等,它从调用的函数获取两种结果:要么此次调用成功进行了;要么系统返回错误标识告诉调用者当前资源不可用,你再等等或者再试度看吧。比如rad()操作,如果当前sockt无数据可读,则立即返回EWOULBLOCK/EAGAIN,告诉调用rad()者”数据还没准备好,你稍后再试”。

在非阻塞异步调用中,稍有不同。调用函数在立即返回时,还告诉调用者,这次请求已经开始了。系统会使用另外的资源或者线程来完成这次调用操作,并在完成的时候知会调用者(比如通过回调函数)。拿Windows的RadFil()或者POSIX的aio_rad()来说,调用它之后,函数立即返回,操作系统在后台同时开始读操作。

在以上三种IO形式中,非阻塞异步是性能最高、伸缩性最好的。

这篇文章探讨不同的I/O利用机制并提供一种跨平台的设计模式(解决方案)。希望此文可以给于TCP高性能服务器开发者一些帮助,选择最佳的设计方案。下面我们会比较Java、C#、C++各自对探讨方案的实现以及性能。我们在文章的后面就不再提及阻塞式的方案了,因为阻塞式I/O实在是缺少可伸缩性,性能也达不到高性能服务器的要求。

两种IO多路复用方案:RactorandProactor

一般情况下,I/O复用机制需要事件分享器(vntdmultiplxor[1、3])。事件分享器的作用,即将那些读写事件源分发给各读写事件的处理者,就像送快递的在楼下喊:谁的什么东西送了,快来拿吧。开发人员在开始的时候需要在分享器那里注册感兴趣的事件,并提供相应的处理者(vnthandlrs),或者是回调函数;事件分享器在适当的时候会将请求的事件分发给这些handlr或者回调函数。

涉及到事件分享器的两种模式称为:RactorandProactor[1]。Ractor模式是基于同步I/O的,而Proactor模式是和异步I/O相关的。在Ractor模式中,事件分离者等待某个事件或者可应用或个操作的状态发生(比如文件描述符可读写,或者是sockt可读写),事件分离者就把这个事件传给事先注册的事件处理函数或者回调函数,由后者来做实际的读写操作。

而在Proactor模式中,事件处理者(或者代由事件分离者发起)直接发起一个异步读写操作(相当于请求),而实际的工作是由操作系统来完成的。发起时,需要提供的参数包括用于存放读到数据的缓存区,读的数据大小,或者用于存放外发数据的缓存区,以及这个请求完后的回调函数等信息。事件分离者得知了这个请求,它默默等待这个请求的完成,然后转发完成事件给相应的事件处理者或者回调。举例来说,在Windows上事件处理者投递了一个异步IO操作(称有ovrlappd的技术),事件分离者等IOCompltion事件完成[1]。这种异步模式的典型实现是基于操作系统底层异步API的,所以我们可称之为“系统级别”的或者“真正意义上”的异步,因为具体的读写是由操作系统代劳的。

举另外个例子来更好地理解Ractor与Proactor两种模式的区别。这里我们只







































白癜风早期能治愈吗
白癜风的治疗方法

转载请注明原文网址:http://www.helimiaopu.com/cksc/1205.html

------分隔线----------------------------