WFMO_Reactor的与众不同

5 WFMO_Reactor的与众不同

WFMO_ReactorACE_ReactorWindows下的默认实现(为什么不选择ACE_Select_Reactor作为默认实现,可能是基于效率和强大性的考虑),WFMO_Reactor的低层使用的函数WaitForMultipleObjectsWSAEventSelectWSAEnumNetworkEvents。其中WaitForMultipleObjects函数用于处理线程,互斥量,信号灯,事件,定时器等事件,而WSAEventSelect用于处理网络IO事件。

由于Windows API和操作系统的特性不一样,WFMO_Reactor在很多地方的表现和其他平台不一致。 【注】

【注】其实这两个问题在《C++ Network Programming Volume 2 - Systematic Reuse with ACE and Frameworks》中4.4 The ACE_WFMO_Reactor Class有说明。这儿算是借花献佛。

5.1 WFMO_Reactor只能处理62个句柄

由于WaitForMultipleObjects不是一个处理大量事件的函数,其最多处理64个事件句柄,而WFMO_Reactor自身为了处理使用了2个句柄,所以一个WFMO_Rector对象只能处理。

如果你想做大规模的网络接入,62个事件句柄显然是不够的,特别是要同时处理IO事件时,导致这个不足的应该是WFMO_Reactor的设计者的一个选择。在赋予WFMO_Reactor强大的特性的同时,WFMO_Reactor的设计者只能让网络IO事件的数量委屈一下了。

5.2 WRITE_MASK触发机制

WFMO_Reactor 选择的是WindowsWSAEventSelect 函数作为网络的IO的反应器。但是WSAEventSelect函数FD_WRITE的事件处理和传统的IO反应器(select)不同。下面是MSDN的描述。

The FD_WRITE network event is handled slightly differently. An FD_WRITE network event is recorded when a socket is first connected with connect/WSAConnect or accepted with accept/WSAAccept,and then after a send fails with WSAEWOULDBLOCK and buffer space becomes available. Therefore,an application can assume that sends are possible starting from the first FD_WRITE network event setting and lasting until a send returns WSAEWOULDBLOCK. After such a failure,the application will find out that sends are again possible when an FD_WRITE network event is recorded and the associated event object is set.

简单翻译就是,只有在三种条件下,WSAEventSelect才会发出FD_WRITE通知,一是使用connectWSAConnect,一个套接字成功建立连接后;二是使用acceptWSAAccept套接字被接受以后;三是若sendWSASendsendtoWSASendTo函数返回失败,而且错误WSAEWOULDBLOCK错误后,缓冲区的空间再次变得可用时。【注】

【注】这种触发方式在IO反应器或者说IO多路复用模型中应该被称为边缘触发方式。select函数好像没有这种触发方式而是水平触发方式, Epoll支持这种方式的,但是默认还是水平触发,这种方式可能有更高的效率,但是代码更加难写。

可以这么理解,WSAEventSelect认为套接字基本都是可写状态,它认为你应该大胆send。只有send出现WSAEWOULDBLOCK失败后,你才需要使用WSAEventSelect反应器。【注】

所以对于WFMO_Reactor的,你不可能依靠注册(或者是唤醒)IO句柄进行写操作,WMFO_Reactor很有可能不会去回调你的handle_output函数

【注】对于网络套接字,只要缓冲区还有空间就可以直接发送,除非缓冲区没有空间了,才可能出现阻塞错误,所以直接send失败的可能性很小,另外反复调用注册IO句柄一类的操作其实是比较耗时的。其实先send,如果send失败再注册IO句柄到反应器的方式应该是一种更加高效的方式,高压力的通讯服务器应该选择这个编写方式。

我自己的通信服务器通过这个改造,提高的性能15%左右(cpu占用率下降)。

由于WFMO_Reactor的这些特点,其实很大的限制了Reactor的可移植性。其实个人感觉如果你对系统特性没有那么多要求,在Windows下选择Select_Reactor替换WFMO_Reactor是更好的选择。

相关文章

导入moment 使用方式 年月日,时分秒 星期几 相对时间 7天后 2小时后 明天 将毫秒转换成年月日
@ 一、前言 为什么介绍redux-actions呢? 第一次见到主要是接手公司原有的项目,发现有之前的大佬在处理...
十大React Hook库 原文地址:https://dev.to/bornfightcompany/top-10-react-hook-libraries-4065 原文...
React生命周期 React的生命周期从广义上分为挂载、渲染、卸载三个阶段,在React的整个生命周期中提供很...
React虚拟DOM的理解 Virtual DOM是一棵以JavaScript对象作为基础的树,每一个节点可以将其称为VNode,用...
React中JSX的理解 JSX是快速生成react元素的一种语法,实际是React.createElement(component, props, ....