C++ 中大家使用什么样的事件模型?

216 views
Skip to first unread message

WL

unread,
Feb 20, 2006, 7:47:33 PM2/20/06
to 高性能网络编程邮件列表
很明显 C++ 里面没有一个很好的事件模型,除了 VC7
的统一事件模型之外,不知道大家都用的什么样的事件模型,都是自己写的吗?VC7的统一事件模型不知道性能、开销如何,文档太少了。

sunway

unread,
Feb 20, 2006, 8:55:18 PM2/20/06
to 高性能网络编程邮件列表
呵呵,我以前用DELPHI比较多,DELPHI的OnButtonClick之类的事件模型非常不错,我一直稀饭用。
而且实现一些很好的设计模式。
C++里可以自己实现一套类似的机制,利用对象函数指针配合模板。
就我所知 loki里有一套类似的机制。

sunway

unread,
Feb 20, 2006, 9:01:04 PM2/20/06
to 高性能网络编程邮件列表
一般的对象事件机制是这样(DELPHI中的机制。估计C++也一样)
typedef struct tagOBJEvent
{
class * pObj; //对象指针,作为函数第一个参数传递
funcptr * pFunc; // 函数地址
}COBJEVENT,*POBJEVENT;

调用的时候 编译器 COBJEVENT cEvent;
cEvent.pFunc(pObj,...) ; //参数列表

closeall

unread,
Feb 20, 2006, 9:02:03 PM2/20/06
to dev4s...@googlegroups.com
我初涉这个领域,不太理解你们所说的事件模型到底指得什么?就是说一件事件完成后在某个地方得到通知么?如果是这个意思的话,在windows的环境下有个事件内核对象。


sunway

unread,
Feb 20, 2006, 9:06:09 PM2/20/06
to 高性能网络编程邮件列表
因为发帖者提到的
C++,如果是内核事件的话这个是操作系统相关的。应该不是这种机制。
我估计是那种语言级 的事件机制。

Schidler zhong

unread,
Feb 20, 2006, 9:11:05 PM2/20/06
to dev4s...@googlegroups.com
to SunWay:
这好像用到了回调机制,不知是吗?

WL

unread,
Feb 20, 2006, 9:37:23 PM2/20/06
to 高性能网络编程邮件列表
我的意思就是:存在着A、B
2种对象,当A对象状态发生变化时候,B应该得到这样的通知。用设计模式的观点来说的话,这个就是“观察者模式”,也就是A是事件主体(Subject),B是事件观察者(Observer)。
具体语言上实现,一般就是实现为一个回调,B将自己注册到A中,当A某事件触发时候,会调用B的某个方法。用接口来描述就是下面这个:

//interface the all observer classes should implement
public interface IObserver
{
void Notify(object anObject);
}//IObserver

//interface that all observable classes should implement
public interface IObservable
{
void Register(IObserver anObserver);
void UnRegister(IObserver anObserver);
}//IObservable

下面就需要B 对象在 Notify 中,通过大量的Switch case
或者if else
来实现不同事件的不同处理。很显然当事件很多的时候,这个简直就是噩梦了。

.NET
里面没有使用上述的接口,而是使用了代理(Delegate)。这就更加简化了事件的处理。但是在
C++
中好像还没有什么好的办法。现在VC7中新增的统一事件模型,它新增了__hook,
__raise
等等几个不符合标准的关键字,的确能很直观的解决问题,但是不知道其效率、开销如何,不太敢使用,不知道哪位朋友有这方面的经验,或者有其他的解决办法。

sunway

unread,
Feb 20, 2006, 9:50:55 PM2/20/06
to 高性能网络编程邮件列表
恩,我猜你的想法就是我后来描述的

class A;
{
public:
COBJEVENT m_Event;
.....
}

使用的时候
A * pObject=new A;
//开始HOOK这个事件
pObject->m_Event=this->Func;
// unhook
pObject->m_Evnet=NULL;

//在A的代码里
A::Dothing()
if m_Event.pFunc!=NULL
//编译器做相关的代码
m_Event(this,.....);

这样使用最简单,
和目前的C#方式一样,不过C#是抄袭DELPHI的方式比注册方式还要简单,而且语法要
好看的多.

用摸版的实现办法可以看游戏编程jincui

luo licun

unread,
Feb 20, 2006, 9:58:49 PM2/20/06
to dev4s...@googlegroups.com
hi,
  同感,觉的delphi的事件很好用,不过说白了就是一个函数指针。WINDOWS一些api有回调函数,好象也是用这个东西。

 
2006/2/21, sunway <sunh...@gmail.com>:

WL

unread,
Feb 20, 2006, 10:01:46 PM2/20/06
to 高性能网络编程邮件列表
//开始HOOK这个事件
pObject->m_Event=this->Func;

中这里面 this->Func
怕是需要静态函数吧,直接调用成员函数估计会有一点难度。

sunway

unread,
Feb 20, 2006, 10:09:01 PM2/20/06
to 高性能网络编程邮件列表
直接调用成员函数是可以的,因为可以使用C++的成员函数指针,

下面就是例子
typedef void ( CEVENTPTR::* CObjectFuncPtr )(int nCount)

这样就可以了,我后面的一些代码是编译器实现的

if m_Event.pFunc!=NULL
//编译器做相关的代码
m_Event(this,.....);

sharon

unread,
Feb 20, 2006, 10:10:07 PM2/20/06
to dev4s...@googlegroups.com
Hi all,
关于事件处理模型,怎么没人提到ACE的Reactor呢?我们现在用的就是它。
 

sunway

unread,
Feb 20, 2006, 10:13:06 PM2/20/06
to 高性能网络编程邮件列表
Reactor是虚基类接口。确实也是回调,
但是感觉和本文讨论的问题有一些差别

sunway

unread,
Feb 20, 2006, 10:16:52 PM2/20/06
to 高性能网络编程邮件列表
不完全是函数指针,是一个结构体

typedef struct tagOBJEvent
{
class * pObj;
//对象指针,作为函数第一个参数传递
funcptr * pFunc; // 函数地址
}COBJEVENT,*POBJEVENT;

里面包含了 this
指针。和普通的函数指针还是有一些差别。

sunway

unread,
Feb 20, 2006, 10:18:29 PM2/20/06
to 高性能网络编程邮件列表
成员函数指针 (转帖)

在C++程序中,很多函数是成员函数,即这些函数是某个类中的一部分。你不可以像一个普通的函数指针那样指向一个成员函数,正确的做法应该是,你必须使用一个成员函数指针。一个成员函数的指针指向类中的一个成员函数,并和以前有相同的参数,声明如下:

float (SomeClass::*my_memfunc_ptr)(int, char *);

//对于使用const关键字修饰的成员函数,声明如下:

float (SomeClass::*my_const_memfunc_ptr)(int, char *) const;

注意使用了特殊的运算符(::*),而“SomeClass”是声明中的一部分。成员函数指针有一个可怕的限制:它们只能指向一个特定的类中的成员函数。对每一种参数的组合,需要有不同的成员函数指针类型,而且对每种使用const修饰的函数和不同类中的函数,也要有不同的函数指针类型。在MSVC中,对下面这四种调用方式都有一种不同的调用类型:__cdecl,
__stdcall, __fastcall, 和
__thiscall。(__thiscall是缺省的方式,有趣的是,在任何官方文档中从没有对__thiscall关键字的详细描述,但是它经常在错误信息中出现。如果你显式地使用它,你会看到“它被保留作为以后使用(it
is reserved for future
use)”的错误提示。)如果你使用了成员函数指针,你最好使用typedef以防止混淆。

将函数指针指向型如float SomeClass::some_member_func(int, char
*)的函数,你可以这样写:

my_memfunc_ptr = &SomeClass::some_member_func;

很多编译器(比如MSVC)会让你去掉“&”,而其他一些编译器(比如GNU
G++)则需要添加“&”,所以在手写程序的时候我建议把它添上。若要调用成员函数指针,你需要先建立SomeClass的一个实例,并使用特殊操作符“->*”,这个操作符的优先级较低,你需要将其适当地放入圆括号内。

SomeClass *x = new SomeClass;

(x->*my_memfunc_ptr)(6, "Another Arbitrary Parameter");

//如果类在栈上,你也可以使用“.*”运算符。

SomeClass y;

(y.*my_memfunc_ptr)(15, "Different parameters this time");

不要怪我使用如此奇怪的语法——看起来C++的设计者对标点符号有着由衷的感情!C++相对于C增加了三种特殊运算符来支持成员指针。“::*”用于指针的声明,而“->*”和“.*”用来调用指针指向的函数。这样看起来对一个语言模糊而又很少使用的部分的过分关注是多余的。(你当然可以重载“->*”这些运算符,但这不是本文所要涉及的范围。)

一个成员函数指针可以被设置成0,并可以使用“==”和“!=”比较运算符,但只能限定在同一个类中的成员函数的指针之间进行这样的比较。任何成员函数指针都可以和0做比较以判断它是否为空。与函数指针不同,不等运算符(<,
>, <=, >=)对成员函数指针是不可用的。

成员函数指针的怪异之处

成员函数指针有时表现得很奇怪。首先,你不可以用一个成员函数指针指向一个静态成员函数,你必须使用普通的函数指针才行(在这里“成员函数指针”会产生误解,它实际上应该是“非静态成员函数指针”才对)。其次,当使用类的继承时,会出现一些比较奇怪的情况。比如,下面的代码在MSVC下会编译成功(注意代码注释):

#include “stdio.h”

class SomeClass {

public:

virtual void some_member_func(int x, char *p) {

printf("In SomeClass"); };

};

class DerivedClass : public SomeClass {

public:

// 如果你把下一行的注释销掉,带有 line
(*)的那一行会出现错误

// virtual void some_member_func(int x, char *p) { printf("In
DerivedClass"); };

};

int main() {

//声明SomeClass的成员函数指针

typedef void (SomeClass::*SomeClassMFP)(int, char *);

SomeClassMFP my_memfunc_ptr;

my_memfunc_ptr = &DerivedClass::some_member_func; // ---- line (*)

return 0;

}

奇怪的是,&DerivedClass::some_member_func是一个SomeClass类的成员函数指针,而不是DerivedClass类的成员函数指针!(一些编译器稍微有些不同:比如,对于Digital
Mars
C++,在上面的例子中,&DerivedClass::some_member_func会被认为没有定义。)但是,如果在DerivedClass类中重写(override)了some_member_func函数,代码就无法通过编译,因为现在的&DerivedClass::some_member_func已成为DerivedClass类中的成员函数指针!

成员函数指针之间的类型转换是一个讨论起来非常模糊的话题。在C++的标准化的过程中,在涉及继承的类的成员函数指针时,对于将成员函数指针转化为基类的成员函数指针还是转化为子类成员函数指针的问题和是否可以将一个类的成员函数指针转化为另一个不相关的类的成员函数指针的问题,人们曾有过很激烈的争论。然而不幸的是,在标准委员会做出决定之前,不同的编译器生产商已经根据自己对这些问题的不同的回答实现了自己的编译器。根据标准(第5.2.10/9节),你可以使用reinterpret_cast在一个成员函数指针中保存一个与本来的类不相关的类的成员函数。有关成员函数指针转换的问题的最终结果也没有确定下来。你现在所能做的还是像以前那样——将成员函数指针转化为本类的成员函数的指针。在文章的后面我会继续讨论这个问题,因为这正是各个编译器对这样一个标准没有达成共识的一个话题。

在一些编译器中,在基类和子类的成员函数指针之间的转换时常有怪事发生。当涉及到多重继承时,使用reinterpret_cast将子类转换成基类时,对某一特定编译器来说有可能通过编译,而也有可能通不过编译,这取决于在子类的基类列表中的基类的顺序!下面就是一个例子:

class Derived: public Base1, public Base2 // 情况 (a)

class Derived2: public Base2, public Base1 // 情况 (b)

typedef void (Derived::* Derived_mfp)();

typedef void (Derived2::* Derived2_mfp)();

typedef void (Base1::* Base1mfp) ();

typedef void (Base2::* Base2mfp) ();

Derived_mfp x;

对于情况(a),static_cast<Base1mfp>(x)是合法的,而static_cast<Base2mfp>(x)则是错误的。然而情况(b)却与之相反。你只可以安全地将子类的成员函数指针转化为第一个基类的成员函数指针!如果你要实验一下,MSVC会发出C4407号警告,而Digital
Mars
C++会出现编译错误。如果用reinterpret_cast代替static_cast,这两个编译器都会发生错误,但是两种编译器对此有着不同的原因。但是一些编译器对此细节置之不理,大家可要小心了!

标准C++中另一条有趣的规则是:你可以在类定义之前声明它的成员函数指针。这对一些编译器会有一些无法预料的副作用。我待会讨论这个问题,现在你只要知道要尽可能得避免这种情况就是了。

需要值得注意的是,就像成员函数指针,标准C++中同样提供了成员数据指针(member
data
pointer)。它们具有相同的操作符,而且有一些实现原则也是相同的。它们用在stl::stable_sort的一些实现方案中,而对此很多其他的应用我就不再提及了。

成员函数指针的使用

现在你可能会觉得成员函数指针是有些奇异。但它可以用来做什么呢?对此我在网上做了非常广泛的调查。最后我总结出使用成员函数指针的两点原因:

* 用来做例子给
C++初学者看,帮助它们学习语法;或者

* 为了实现“委托(
delegate)”!

成员函数指针在STL和Boost库的单行函数适配器(one-line
function
adaptor)中的使用是微不足道的,而且允许你将成员函数和标准算法混合使用。但是它们最重要的应用是在不同类型的应用程序框架中,比如它们形成了MFC消息系统的核心。

当你使用MFC的消息映射宏(比如ON_COMMAND)时,你会组装一个包含消息ID和成员函数指针(型如:CCmdTarget::*成员函数指针)的序列。这是MFC类必须继承CCmdTarget才可以处理消息的原因之一。但是,各种不同的消息处理函数具有不同的参数列表(比如OnDraw处理函数的第一个参数的类型为CDC
*),所以序列中必须包含各种不同类型的成员函数指针。MFC是怎样做到这一点的呢?MFC利用了一个可怕的编译器漏洞(hack),它将所有可能出现的成员函数指针放到一个庞大的联合(union)中,从而避免了通常需要进行的C++类型匹配检查。(看一下afximpl.h和cmdtarg.cpp中名为MessageMapFunctions的union,你就会发现这一恐怖的事实。)因为MFC有如此重要的一部分代码,所以事实是,所有的编译器都为这个漏洞开了绿灯。(但是,在后面我们会看到,如果一些类用到了多重继承,这个漏洞在MSVC中就不会起作用,这正是在使用MFC时只能必须使用单一继承的原因。)

在boost::function中有类似的漏洞(但不是太严重)。看起来如果你想做任何有关成员函数指针的比较有趣的事,你就必须做好与这个语言的漏洞进行挑战的准备。要是你想否定C++的成员函数指针设计有缺陷的观点,看来是很难的。

在写这篇文章中,我有一点需要指明:“允许成员函数指针之间进行转换(cast),而不允许在转换完成后调用其中的函数”,把这个规则纳入C++的标准中是可笑的。首先,很多流行的编译器对这种转换不支持(所以,转换是标准要求的,但不是可移植的)。其次,所有的编译器,如果转换成功,调用转换后的成员函数指针时仍然可以实现你预期的功能:那编译器就没有所谓的“undefined
behavior(未定义的行为)”这类错误出现的必要了(调用(Invocation)是可行的,但这不是标准!)。第三,允许转换而不允许调用是完全没有用处的,只有转换和调用都可行,才能方便而有效地实现委托,从而使这种语言受益。

为了让你确信这一具有争议的论断,考虑一下在一个文件中只有下面的一段代码,这段代码是合法的:

class SomeClass;

typedef void (SomeClass::* SomeClassFunction)(void);

void Invoke(SomeClass *pClass, SomeClassFunction funcptr) {

(pClass->*funcptr)(); };

注意到编译器必须生成汇编代码来调用成员函数指针,其实编译器对SomeClass类一无所知。显然,除非链接器进行了一些极端精细的优化措施,否则代码会忽视类的实际定义而能够正确地运行。而这造成的直接后果是,你可以“安全地”调用从完全不同的其他类中转换过来的成员函数指针。

为解释我的断言的另一半——转换并不能按照标准所说的方式进行,我需要在细节上讨论编译器是怎样实现成员函数指针的。我同时会解释为什么使用成员函数指针的规则具有如此严格的限制。获得详细论述成员函数指针的文档不是太容易,并且大家对错误的言论已经习以为常了,所以,我仔细检查了一系列编译器生成的汇编代码…

Message has been deleted

WL

unread,
Feb 20, 2006, 10:32:16 PM2/20/06
to 高性能网络编程邮件列表
如果需要多个观察者呢,还需要一个成员函数指针容器吧

sharon

unread,
Feb 20, 2006, 11:01:34 PM2/20/06
to dev4s...@googlegroups.com
Reactor不是一个虚基类接口,事件处理器ACE_Event_Handler才是。Reactor一般是以单件的形式在程序里被使用。用户需要从Event_Handler派生出自己的子类,向Reactor注册;Reactor收到事件或者信号时,会调用该子类的相应方法。
假设Reactor是A对象,Event_Handler是B对象,我觉得Reactor模式与这里讨论的问题不一样的地方在于:
事件不是A对象所发生的,而是B对象本来要获取的,只是统一在A对象中去获取了。
不过总体说来,我觉得Reactor模式其实是解决了楼主想要解决的问题啊,不知道是不是我理解错了,:$

 
On 2/21/06, sunway <sunh...@gmail.com> wrote:

sunway

unread,
Feb 20, 2006, 11:42:06 PM2/20/06
to 高性能网络编程邮件列表
恩,我刚才大致看了下ACE的东西,我记错了,Reactor不是虚基类。
对于这个问题loki库提供了一个实现。大家可以找来看看。他支持=操
作去设置回调的

sunway

unread,
Feb 20, 2006, 11:43:45 PM2/20/06
to 高性能网络编程邮件列表
这个就是多播(C#中的做法),当然要list或者vector只类的容器了,C#是支持多播的。
这个只是实现的细节,看需求来决定是否使用多播。

WL

unread,
Feb 21, 2006, 12:40:49 AM2/21/06
to 高性能网络编程邮件列表
其实我就是想要一种使用起来,简洁高效的类似.NET中
delegate 的咚咚!

sunway

unread,
Feb 21, 2006, 12:45:41 AM2/21/06
to 高性能网络编程邮件列表
用对象函数指针自己实现一个也是很容易的。

leowu2000

unread,
Feb 21, 2006, 12:49:31 AM2/21/06
to dev4s...@googlegroups.com
我觉得大家聊天的话还是使用im比较好.
邮件的内容嘛,尽量自己想全了再回复,不然看着感觉是一堆的垃圾邮件.
谢谢.

sunway 写道:
> 用对象函数指针自己实现一个也是很容易的。
>
>
>

closeall

unread,
Feb 21, 2006, 12:56:51 AM2/21/06
to dev4s...@googlegroups.com
其实我个人这种方式很好,有点像bbs的感觉,但是他又是一种新的交流方式。当然口味难调。各有优缺点。至于像垃圾邮件,我到不这么认为,google这一点做得很好

2006/2/21, leowu2000 <leow...@gmail.com>:

sunway

unread,
Feb 21, 2006, 1:00:44 AM2/21/06
to 高性能网络编程邮件列表
随意一点好,而且大家一般白天都在工作,偶尔看一下Group,看到有新的想法回一下,
要什么都想全了,还要讨论干吗?

Donald

unread,
Feb 21, 2006, 1:18:58 AM2/21/06
to dev4s...@googlegroups.com
ACE中的reactor和practor都是事件模型,还有ACK
似乎用ACE开发网游的不是很多啊,为什么呢?

2006/2/21, sunway <sunh...@gmail.com>:


> 随意一点好,而且大家一般白天都在工作,偶尔看一下Group,看到有新的想法回一下,
> 要什么都想全了,还要讨论干吗?
>
>
>


--
Donald

Donald

unread,
Feb 21, 2006, 1:20:14 AM2/21/06
to dev4s...@googlegroups.com
一个事件模型也是比较容易实现的
主要是回调点的处理不同而产生了各种不同的事件模型


在 06-2-21,Donald<flyi...@gmail.com> 写道:


--
Donald

sunway

unread,
Feb 21, 2006, 1:25:08 AM2/21/06
to 高性能网络编程邮件列表
主要是回调点的处理不同而产生了各种不同的事件模型
?
不明白
现在用ACE开发游戏的就我知道的有几家,但是都是
小公司,没有技术实力做低层框架。
同时我看过一些ACE的书。感觉各种基础类比较丰富
但是稍微麻烦了一些。而且BUG也不少。
我们公司有项目组据说用过,后来放弃了,原因是麻
烦。

sharon

unread,
Feb 21, 2006, 1:36:36 AM2/21/06
to dev4s...@googlegroups.com
我们公司是做通信的,ACE我们用了一年了,开始用的时候好象问题比较多,后来发现问题其实都是我们自己没用好引起的,暂时还没发现ACE有什么BUG啊,呵呵。看来我们的水平比较次,:P

On 2/21/06, sunway <sunh...@gmail.com> wrote:

Donald

unread,
Feb 21, 2006, 1:39:26 AM2/21/06
to dev4s...@googlegroups.com
我不知道同各位理解的事件是否一样
我接触的事件模型都用在GUI和通讯框架中
事件模型无外乎事件的通知方式,以便能够回调自定义的事件处理代码
所以,各种回调方式的不同,就产生了不同的事件模型
比如
MFC的callback
Swing、MINA、Cindy的Listener
ACE的ACK、Proactor、Reactor
还有OSGI的White Board方式
甚至*nix上的signal
都是不同的事件回调点产生了不同的事件模型,WDYT?

我个人觉得ACE已经做的很不错了
麻烦我倒没觉得,可能是早在使用ACE之前就已经研究过很多网络框架的原因吧
基本上跟POSA2里面描述的没啥出入
不知道自己做底层框架做出来都是什么架构呢?
我很好奇

BUG不少?比如说呢?
老实说,ACE我现在也只是看,还没机会具体使用,有经验的不妨说一说啊

2006/2/21, sunway <sunh...@gmail.com>:


--
Donald

sunway

unread,
Feb 21, 2006, 1:41:56 AM2/21/06
to 高性能网络编程邮件列表
我有个同事专心研究ACE一年多把,用ACE也做过一些东西,他说(去年年初)ACE的BUG不少
服务器端程序测试下来性能一般。后来他就不用ACE了。

Donald

unread,
Feb 21, 2006, 1:45:36 AM2/21/06
to dev4s...@googlegroups.com
:)
有机会还是要请你那位同事出来布布道啊
2006/2/21, sunway <sunh...@gmail.com>:

> 我有个同事专心研究ACE一年多把,用ACE也做过一些东西,他说(去年年初)ACE的BUG不少
> 服务器端程序测试下来性能一般。后来他就不用ACE了。
>
>
>


--
Donald

sunway

unread,
Feb 21, 2006, 1:48:32 AM2/21/06
to 高性能网络编程邮件列表
一般的架构是指MMORPG的TCP/UDP组件。还包含内存管理,线程池等其他组件。
一般对于MMO
服务器端来说,基本上没有跨平台的可能。所以一般都是针对某
个平台进行优化,LINUX下EPOLL,win下是IOCP、其他重叠I/O。所以这种情况
下ACE基本上没什么用。就我说知道的,网易,腾讯,盛大
现在的大部分应用
都没有使用ACE。其他行业我就知道华为应该是使用过ACE的,因为我看过他们
内部出来的ACE教程。

Donald

unread,
Feb 21, 2006, 2:21:11 AM2/21/06
to dev4s...@googlegroups.com
用ACE可能主要还是为了跨平台吧
至少我想用它的目的是为了这个

2006/2/21, sunway <sunh...@gmail.com>:


--
Donald

Roger Chen

unread,
Feb 21, 2006, 2:33:28 AM2/21/06
to dev4s...@googlegroups.com
To sunway:

你们用什么工具测试服务器端性能?标准的工具还是自己写的?

--
Roger Chen <che...@gmail.com>

sunway

unread,
Feb 21, 2006, 2:44:12 AM2/21/06
to 高性能网络编程邮件列表
机器人程序测试,看CPU占用率,最简单的办法。

sunbi...@gmail.com

unread,
Feb 26, 2006, 3:55:45 AM2/26/06
to 高性能网络编程邮件列表
总结几点ACE的缺点,请大家拍板:
1. 听说ACE的效率不是非常高(道听途说,不是很肯定).
现在很多网游还都是用纯c写的,应该是处于效率方面的考虑吧.
2.
ACE为了实现跨平台,基本上把所有的api都封装了个遍,学习曲线比较陡峭.
3. 出了bug很难调试.

Hu Yi

unread,
Feb 26, 2006, 5:18:08 AM2/26/06
to dev4s...@googlegroups.com
〉〉1. 听说ACE的效率不是非常高(道听途说,不是很肯定).
〉〉现在很多网游还都是用纯c写的,应该是处于效率方面的考虑吧.
ACE作者自称是效率非常高的,和直接用c相差无几,这也是ACE追求的目标,应用得当,可能比自己手写代码还快,毕竟在封装易用性的同时,也封装了很多专家知识进去。
我没有对比过,也无法单从效率上来说明两种做法的好坏,毕竟现在单纯追求效率的软件太少了。
〉〉2.
〉〉ACE为了实现跨平台,基本上把所有的api都封装了个遍,学习曲线比较陡峭.
ACE封装API,易用性并没有降低,只不过是把原来的API移植到了一个新的命名空间下,原来怎么用,现在还怎么用 ,而且现在是跨平台的。
〉〉3. 出了bug很难调试.
ACE中大量使用了IoC,这类程序难调试是必然的了,但是几乎所有框架级的东西,都有这个毛病,牵扯上多线程,就更复杂了。

Donald

unread,
Feb 26, 2006, 7:40:40 AM2/26/06
to dev4s...@googlegroups.com
关于ACE效率不好的说法倒是第一次听说
从我看到的ACE框架中,处处都体现着效率第一的设计思想

在 06-2-26,sunbi...@gmail.com<sunbi...@gmail.com> 写道:


--
Donald
My Blog:http://flyingbug.blogjava.net

大宝(sodme)

unread,
Feb 26, 2006, 11:36:07 AM2/26/06
to dev4s...@googlegroups.com
hi all:
我只听说过由于ACE框架太大,暂时没法把握而没采用它的,还没有听说过由于ACE存在无法解决的重大BUG而拒绝采用它的。


--
Best regards
大宝(sodme)
msn : sod...@hotmail.com
Email : sodm...@gmail.com

sunbi...@gmail.com

unread,
Feb 27, 2006, 8:46:24 AM2/27/06
to 高性能网络编程邮件列表
hehe,我的意思不是说ACE有bug,而是我自己写的程序有bug。
偶现在正处于ACE学习的初级阶段,还没有用它搭过像样的应用,ACE的源码更是没有信心和时间去研究,继续学习。。。。。

alvi...@gmail.com

unread,
Feb 27, 2006, 11:22:47 AM2/27/06
to 高性能网络编程邮件列表

露个脸,也来说二句。我用ACE一年左右,学了非常多东西,用起来是越来越顺手,ACE的架构模型是非常先进的,就模型上来说起码先进其他语言平台5到10年,看看Java的nio,J2SE5.0的Concurrency吧。

ACE中各个操作系统的差异屏蔽的还是很好的。在框架和包装上有一些参差不齐的感觉,Smit博士和一些学生写的非常不错,还有一些就一般般了,但是这个框架是很健壮的,只是有些瑕疵而已。再就是由于涉及的面太广,C++语言自身的复杂性来说,门槛比较高,能用好不容易,做大系统就应该使用它的思想,如果有精力的话可以不用他的实现,那样你要做非常多的工作。

如果小系统,它的框架可能会把问题搞复杂也发挥不了它的优势,但是如果只用到对象包装那一层,而不是框架层,它也会为你省下非常多的工作,特别是用C++开发的话。如果要做的不是核心系统,而是业务层那就要TAO实现的Corba,或者ICE,J2EE,.net那些了。

也说点感想,如果ACE能象ICE那样那样支持多语言、代码清晰的话就好了,如果在屏蔽操作系统差异的时候多用点C++中基于policy-based策略划分来屏蔽操作系统差异和功能组合的话,而不是过多的应用OO的多态,那就更好了,不过这也有代码的历史原因和模版的一些缺点导致的。

说起ACE的Bug我也发现过一个,Proactor还有ACE_DLL等几个,也不是什么大不了的,就象以前ACE和MFC还有Winmian程序的内存泄露问题一样。内存在是因为ACE有自己的内存管理机制,在非mian入口的程序需要手动初试化,ACE框架中只帮mian做了替换而已。Proactor和ACE_DLL基本上也都是在他们的开发版本中出现的,二处内存泄露,也不影响使用。我提交Bug后Smit博士亲自负责维护,而且Bug很快在后来的稳定版本中解决了。

为ACE辟谣,虽然她的实现不是那样的理想,但是里面的模型思想,真是一个宝藏!
(喜欢高能和分布式网络编程的朋友们,和你们交个朋友,多多指教、切磋、共同进步,我的blog:http://wolf.bloghome.cn

Donald

unread,
Feb 27, 2006, 9:11:23 PM2/27/06
to dev4s...@googlegroups.com
呵呵,欢迎楼上的兄弟,不过你的blog很久没更新了^_^

2006/2/28, alvi...@gmail.com <alvi...@gmail.com>:

Roger Chen

unread,
Feb 27, 2006, 9:16:39 PM2/27/06
to dev4s...@googlegroups.com
To avlin:

On Mon, 27 Feb 2006 16:22:47 -0000
"alvi...@gmail.com" <alvi...@gmail.com> 撰写于:

>
> 露个脸,也来说二句。我用ACE一年左右,学了非常多东西,用起来是越来越顺手,ACE的架构模型是非常先进的,就模型上来说起码先进其他语言平台5到10年,看看Java的nio,J2SE5.0的Concurrency吧。
>

能稍微描述一下这先进的5到10年体现在什么地方吗?

--
Roger Chen <che...@gmail.com>

alvi...@gmail.com

unread,
Feb 28, 2006, 2:04:22 AM2/28/06
to 高性能网络编程邮件列表
是啊,忙啊,没人讨论写的蛮没意思的。

Donald 写道:

alvi...@gmail.com

unread,
Feb 28, 2006, 3:31:16 AM2/28/06
to 高性能网络编程邮件列表
就拿Proactor,Reactor,Task,Stream框架来说。Java里的Nio也都停留在select,poll的模型上,而且是前几年才加入的。连接、关闭等事件响应是异步的,但是读写仍然是同步的,算是半异步的模型。象Proactor包装的IOCP和Posix
AIO,所有的事件都可以是异步的,包括数据的读写,也都交给系统内核去完成后通知了,这对服务器的磁盘操作来说是非常有利的。也包括网络IO,网络IO在高负载的时候可以选用,降低并发线程占用的资源。

再按模型来说,Reactor的事件通知、Proactor的异步模型,Java,.net的网络模型还没有达到这个高度,这里只指的是网络通讯的模型,不是应用服务器这样的业务应用层次,也算是系统层。

象java的Concurrency包,就是个很好的例子,几乎的就是照着ACE的Task框架来的,看看C++网络编程二卷和ACE编程指南APG,中的相关例子吧。

ACE是个实现,可能感觉上没有很多商业的产品那么易用和全面,但是这就好比学术和工业,她所支撑和实现的是一个理论模型,而不是商业化的产品。商业化的产品会变,也许过个二年它又会新瓶旧酒又来一遍。就好比各种类Unix和Unix的思想一样,能说Linux就比那些老的Unix系统先进吗?实际上很多Linux的新特性,那些商用、非商用的Unix很早也有,只不过他很好的借助了GNU的力量。Unix的模型和思想能否定吗?我想POSA的模型也经过锤炼了的,是从工程实践中提取的学术模型,我们可能总会忽略理论模型,但实用技术研究到了深的层次又会回归到理论,因为那才是精髓。

而那些商业产品和平台不都还在挣扎么,为的是什么,是更快的响应市场、靠语法糖笼络开发人员,巩固他们的平台,占有市场,以获得各种利润。如果他们给你的是多么先进强大如何美妙的开发平台产品,往往你很难清晰的理解他们的平台框架和思想,因为你就是他们的实验品。他们的大师给你定义游戏规则,系统级开发也就没有我们的地盘了,我们永远是沉睡的neo。

(说先进,确切的说是ACE的模型,POSA所描述的那些,那些流行的商业平台在网络通讯模型上是没有说在哪以项上推翻或者超越的,顶多是新的一些模型。)

Roger Chen 写道:

Message has been deleted

Roger Chen

unread,
Feb 28, 2006, 4:14:02 AM2/28/06
to dev4s...@googlegroups.com

On Tue, 28 Feb 2006 08:31:16 -0000
"alvi...@gmail.com" <alvi...@gmail.com> 撰写于:

> 就拿Proactor,Reactor,Task,Stream框架来说。Java里的Nio也都停留在select,poll的模型上,而且是前几年才加入的。连接、关闭等事件响应是异步的,但是读写仍然是同步的,算是半异步的模型。象Proactor包装的IOCP和Posix
> AIO,所有的事件都可以是异步的,包括数据的读写,也都交给系统内核去完成后通知了,这对服务器的磁盘操作来说是非常有利的。也包括网络IO,网络IO在高负载的时候可以选用,降低并发线程占用的资源。
>

NIO所采用的是Reactor的模型。所有的事件都是异步的,包括连接、关闭、读、写
。但不同的地方在于,NIO异步读、写时会即时得到响应结果,而不是等事件完成
后才通过通知机制得到。

我对C++的网络开发不熟悉,不过我看到过sodme的这篇文章:
http://blog.csdn.net/sodme/archive/2006/02/15/599132.aspx,觉得NIO的这种
机制应该和epoll是一样的。

实际上这种机制给了应用更大的弹性。基于nio,可以设计出各种应用模型。当然
,也带来了缺点,就是可能没有直接在内核完成操作然后通知应用来得高效。


> 再按模型来说,Reactor的事件通知、Proactor的异步模型,Java,.net的网络模型还没有达到这个高度,这里只指的是网络通讯的模型,不是应用服务器这样的业务应用层次,也算是系统层。
>
> 象java的Concurrency包,就是个很好的例子,几乎的就是照着ACE的Task框架来的,看看C++网络编程二卷和ACE编程指南APG,中的相关例子吧。

这个就不好评价了,我根本不了解ACE的Task框架。但是我并不认为concurrent包
是照着Task框架来的,JSR 166专家组绝对不是吃素的。

但我认为它们之间肯定会有类似的地方,就好像可以说Java里面a+b就是照着C里面
的a+b来的。

>
> ACE是个实现,可能感觉上没有很多商业的产品那么易用和全面,但是这就好比学术和工业,她所支撑和实现的是一个理论模型,而不是商业化的产品。商业化的产品会变,也许过个二年它又会新瓶旧酒又来一遍。就好比各种类Unix和Unix的思想一样,能说Linux就比那些老的Unix系统先进吗?实际上很多Linux的新特性,那些商用、非商用的Unix很早也有,只不过他很好的借助了GNU的力量。Unix的模型和思想能否定吗?我想POSA的模型也经过锤炼了的,是从工程实践中提取的学术模型,我们可能总会忽略理论模型,但实用技术研究到了深的层次又会回归到理论,因为那才是精髓。
>
> 而那些商业产品和平台不都还在挣扎么,为的是什么,是更快的响应市场、靠语法糖笼络开发人员,巩固他们的平台,占有市场,以获得各种利润。如果他们给你的是多么先进强大如何美妙的开发平台产品,往往你很难清晰的理解他们的平台框架和思想,因为你就是他们的实验品。他们的大师给你定义游戏规则,系统级开发也就没有我们的地盘了,我们永远是沉睡的neo。
>
> (说先进,确切的说是ACE的模型,POSA所描述的那些,那些流行的商业平台在网络通讯模型上是没有说在哪以项上推翻或者超越的,顶多是新的一些模型。)
>

这个就太远了,没有人否定POSA2里面的模型,事实上大部分做网络应用的人也就
是在POSA2里面转圈圈。

但说到模型,实际上是更为宏观的一个层面,所以我并不认可你说的ACE的模型领
先其他语言平台5到10年。

假设在window系统没有提供iocp以前,能不能用select做出一个proactor模型来?
当然可以,只不过效率方面比不上而已。java里面的nio也是如此,它提供的只是
一个比较底层一点的api,基于这些api,使用者可以搭建出各种各样的模型,只不
过效率上会有一些问题,这是硬伤。

JSR 203也早提出在java中加入新的异步I/O,这就相当于可以利用各个操作系统级
的实现,不过一直没有人推动这件事情。

我认可ACE,认可POSA2。但是我认为你的靶子打错了。


> Roger Chen 写道:
>
> > To avlin:
> >
> > On Mon, 27 Feb 2006 16:22:47 -0000
> > "alvi...@gmail.com" <alvi...@gmail.com> 撰写于:
> >
> > >
> > > 露个脸,也来说二句。我用ACE一年左右,学了非常多东西,用起来是越来越顺手,ACE的架构模型是非常先进的,就模型上来说起码先进其他语言平台5到10年,看看Java的nio,J2SE5.0的Concurrency吧。
> > >
> >
> > 能稍微描述一下这先进的5到10年体现在什么地方吗?
> >
> > --
> > Roger Chen <che...@gmail.com>
>
>

--
Roger Chen <che...@gmail.com>

Message has been deleted
Message has been deleted

alvi...@gmail.com

unread,
Feb 28, 2006, 5:48:20 AM2/28/06
to 高性能网络编程邮件列表
Roger Chen 写道:

> On Tue, 28 Feb 2006 08:31:16 -0000
> "alvi...@gmail.com" <alvi...@gmail.com> 撰写于:
>
> > 就拿Proactor,Reactor,Task,Stream框架来说。Java里的Nio也都停留在select,poll的模型上,而且是前几年才加入的。连接、关闭等事件响应是异步的,但是读写仍然是同步的,算是半异步的模型。象Proactor包装的IOCP和Posix
> > AIO,所有的事件都可以是异步的,包括数据的读写,也都交给系统内核去完成后通知了,这对服务器的磁盘操作来说是非常有利的。也包括网络IO,网络IO在高负载的时候可以选用,降低并发线程占用的资源。
> >
>
> NIO所采用的是Reactor的模型。所有的事件都是异步的,包括连接、关闭、读、写
> 。但不同的地方在于,NIO异步读、写时会即时得到响应结果,而不是等事件完成
> 后才通过通知机制得到。
>
> 我对C++的网络开发不熟悉,不过我看到过sodme的这篇文章:
> http://blog.csdn.net/sodme/archive/2006/02/15/599132.aspx,觉得NIO的这种
> 机制应该和epoll是一样的。
>
> 实际上这种机制给了应用更大的弹性。基于nio,可以设计出各种应用模型。当然
> ,也带来了缺点,就是可能没有直接在内核完成操作然后通知应用来得高效。

是Reactor的处理过程要利用线程池,或者单线程并行,NIO的读写也需要在另外的线程里。

>
>
> > 再按模型来说,Reactor的事件通知、Proactor的异步模型,Java,.net的网络模型还没有达到这个高度,这里只指的是网络通讯的模型,不是应用服务器这样的业务应用层次,也算是系统层。
> >
> > 象java的Concurrency包,就是个很好的例子,几乎的就是照着ACE的Task框架来的,看看C++网络编程二卷和ACE编程指南APG,中的相关例子吧。
>
> 这个就不好评价了,我根本不了解ACE的Task框架。但是我并不认为concurrent包
> 是照着Task框架来的,JSR 166专家组绝对不是吃素的。
>
> 但我认为它们之间肯定会有类似的地方,就好像可以说Java里面a+b就是照着C里面
> 的a+b来的。
>

哈哈,我没偏见的,别激动啊。C++,Java我都搞的。C/C++/Java都是同根生,还有什么好争论,只不过是从系统层到业务层,各自占领地盘而已。发个email到JSR
166的专家组问下啊,POSA1/POSA2都很早就出了啊。


> >
> > ACE是个实现,可能感觉上没有很多商业的产品那么易用和全面,但是这就好比学术和工业,她所支撑和实现的是一个理论模型,而不是商业化的产品。商业化的产品会变,也许过个二年它又会新瓶旧酒又来一遍。就好比各种类Unix和Unix的思想一样,能说Linux就比那些老的Unix系统先进吗?实际上很多Linux的新特性,那些商用、非商用的Unix很早也有,只不过他很好的借助了GNU的力量。Unix的模型和思想能否定吗?我想POSA的模型也经过锤炼了的,是从工程实践中提取的学术模型,我们可能总会忽略理论模型,但实用技术研究到了深的层次又会回归到理论,因为那才是精髓。
> >
> > 而那些商业产品和平台不都还在挣扎么,为的是什么,是更快的响应市场、靠语法糖笼络开发人员,巩固他们的平台,占有市场,以获得各种利润。如果他们给你的是多么先进强大如何美妙的开发平台产品,往往你很难清晰的理解他们的平台框架和思想,因为你就是他们的实验品。他们的大师给你定义游戏规则,系统级开发也就没有我们的地盘了,我们永远是沉睡的neo。
> >
> > (说先进,确切的说是ACE的模型,POSA所描述的那些,那些流行的商业平台在网络通讯模型上是没有说在哪以项上推翻或者超越的,顶多是新的一些模型。)
> >
>
> 这个就太远了,没有人否定POSA2里面的模型,事实上大部分做网络应用的人也就
> 是在POSA2里面转圈圈。
>

呵呵,我太情绪化了。当我发彪啊。未来是我们的啊。可惜我们还弱啊。。。很悲哀的。。。特别是在国内。


> 但说到模型,实际上是更为宏观的一个层面,所以我并不认可你说的ACE的模型领
> 先其他语言平台5到10年。
>

说了是网络通讯啊。个人感觉而已,感叹而已。这个应该是不朽的,哪怕多进程阻塞模型都还有人用。不过从系统j层接口来说,这个框架个接口还是不错的。有多语言的版本就更好了。

> 假设在window系统没有提供iocp以前,能不能用select做出一个proactor模型来?
> 当然可以,只不过效率方面比不上而已。java里面的nio也是如此,它提供的只是
> 一个比较底层一点的api,基于这些api,使用者可以搭建出各种各样的模型,只不
> 过效率上会有一些问题,这是硬伤。

是,操作系统的用户空间的资源是有限的,内核空间可以把资源调度的更好,特别是I/O,就好比硬件的轮询、中断、DMA、管道样的。

>
> JSR 203也早提出在java中加入新的异步I/O,这就相当于可以利用各个操作系统级
> 的实现,不过一直没有人推动这件事情。

操作系统异步IO的接口差异太大,难度很大,所以说ACE了不起,但是还不是极致,要把基于模板的Policy-base的策略编程来屏蔽差异和功能划分就好了,就像Loki。

其实也没必要局限在某个单一的平台,特别是商业平台,如果有精力的话。其实技术都是通的,表面的,回归了还是理论,再说白点还是人,人解决问题的方法和思路,还有他们的感受。

>
> 我认可ACE,认可POSA2。但是我认为你的靶子打错了。
>

没有说Java的不好啊,其实Java现在的一些基础设施也开始不错起来啊。如果说还只有老的阻塞IO,那还怎么说呢。NIO的读写的确还没有进入内核态,还是用户在线程池里干的。不过象Posix
aio,iocp,epoll这些除非在比较变态的条件下才使用,各个操作系统的接口差异较大,不过这也算cut
edge的东西吧。

大宝(sodme)

unread,
Feb 28, 2006, 6:16:11 AM2/28/06
to dev4s...@googlegroups.com
引用 alvin的:
-----------------------------------------
不过象Posix aio,iocp,epoll这些除非在比较变态的条件下才使用...
---------------------------------------------

不敢苟同. 你认为高性能的网络应用,只有在BT条件下才会使用吗?我的看法恰恰相反,高性能的应用领域会越来越广泛,而且,可以这样说:任何一个优秀的网络应用系统,都必须解决高并发,高负载的问题,只要他是基于网络的.

alvi...@gmail.com

unread,
Feb 28, 2006, 7:45:47 AM2/28/06
to 高性能网络编程邮件列表
大宝(sodme) 写道:

> 引用 alvin的:
> -----------------------------------------
> 不过象Posix aio,iocp,epoll这些除非在比较变态的条件下才使用...
> ---------------------------------------------
>
> 不敢苟同. 你认为高性能的网络应用,只有在BT条件下才会使用吗?我的看法恰恰相反,高性能的应用领域会越来越广泛,而且,可以这样说:任何一个优秀的网络应用系统,都必须解决高并发,高负载的问题,只要他是基于网络的.
>

哇啊啊,火药味十足啊。
apache没用吧?ICE没用吧。使用线程池方式是编写简单,但是扩展麻烦,而且各session数据不容易同步,线程切换会消耗系统资源。使用异步IO那就是编写麻烦一些,数据处理容易集中进行,易扩充和各session交互,但是数据传递会消耗系统的锁资源,数据需要同步。如果是比较独立的处理,在非高负载的情况下,还是Reactor线程池里效率较高,但是在高压力且数据处理需要交互的情况下使用异步IO是比较好的。我看了C++网络编程和APG里讲过的,异步IO用来处理服务器磁盘文件IO是很好,但是处理网络IO,要求高负载可以,要求效率一般用传统模型,平台接口差异小,程序容易移植。
(大家千万别对我不满啊!个人意见而已,我没攻击你们啊。大家讨论问题,切磋啊。)

大宝(sodme)

unread,
Feb 28, 2006, 8:30:50 AM2/28/06
to dev4s...@googlegroups.com
hi alvin:
呵呵, 没有对你不满, 本身也无所谓对错了. 我只是觉得, 针对于高并发连接的网络应用, 这些高效模型几乎是首选的. 当然,
这也是我的个人意见, 呵呵. apache没用IOCP,效率确实不错,但你能说apache用了IOCP之后效率就不会更好吗?它没有采用IOCP这种与特定平台绑定的高效模型,也可能是为了考虑跨平台能力呢?对一个本身不存在的问题进行假设,我觉得意义本来就不大,对吧。
  说了半天,我都不知道你的观点是什么,我说一下我的观点吧:针对于海量用户连接的网络应用,首选模型还是使用IOCP,EPOLL这样的高效模型,如果你也赞同这一点,那就OK了,没啥好争的了。

alvi...@gmail.com

unread,
Feb 28, 2006, 9:04:53 AM2/28/06
to 高性能网络编程邮件列表
hi,宝哥。
呵呵,我就事论事啊。其实技术都事互补的,都有存在的理由和空间的。每个人都有自己视角的,apache是为了可移植性好的。MySQL火过PostgreSQL就是因为它有Win32的版本。高性能的东西就要利用、渣干特定平台的特性的。海量连接、高并发用异步IO是没错了,没否定的,那就是Cut
edge的东西,其实AIX那样的主机里面也提供内核级POSIX
AIO的支持的。

其实说回来这个主题也很广,不确定的,我谈了下ACE和POSA的看法而已啊,唠嗑了点Java的东西,没有说那个模型好坏么。其实高能网络,在单机不能承载的情况下还可以做集群,做分布式的。
(没有做辩论的想法,先跟大家混个脸熟,呵呵。)

大宝(sodme) 写道:

sunway

unread,
Feb 28, 2006, 9:05:52 AM2/28/06
to 高性能网络编程邮件列表
to alvi...@gmail.com
异步在操作系统就是线程池的方式实现的.
要求效率一般用异步I/O,同时配合用线程池
处理逻辑

Donald

unread,
Feb 28, 2006, 9:35:18 AM2/28/06
to dev4s...@googlegroups.com
>
> 我对C++的网络开发不熟悉,不过我看到过sodme的这篇文章:
> http://blog.csdn.net/sodme/archive/2006/02/15/599132.aspx,觉得NIO的这种
> 机制应该和epoll是一样的。
>
目前的NIO还是基于select实现的,在Linxu2.6内核以后,Mustang(build 69)的NIO使用了Linux的epoll来实现select()

疾风之狼(Alvin.Lee)

unread,
Feb 28, 2006, 9:37:55 AM2/28/06
to 高性能网络编程邮件列表
是,异步IO的端口事件,数据读写不需要线程池来读写,就好像DMA样的。数据读写IO在异步IO上,处理在线程池,或者多个独立线程。

但反应式的读写还是要在线程池里做,一般处理也绑定在线程里。一般反应式做事件通知的消息机制也不错的,比如那些Time
Schedule,事件等等。


sunway 写道:

大宝(sodme)

unread,
Feb 28, 2006, 10:36:51 AM2/28/06
to dev4s...@googlegroups.com
hi alvin:
呵呵, 即使作辩论也无妨. :)
你的观点我同意, 移植性确实是一个很重要的考虑方面. 至于说高性能网络 这一块, 我想不管再怎么作分布式和集群, 其归根结底,
在最终的逻辑上, 还是要靠单个的服务器来提供服务的, 所以单个服务器程序的高性能仍然是很多系统追求的目标. 这确实有点微观+宏观的意思,
如你所言, 角度不同而已.
争论是难免的, 争的有价值就行. 呵呵.

疯子阿虹

unread,
Mar 5, 2006, 10:45:11 PM3/5/06
to 高性能网络编程邮件列表
使用Observer很不错啊,
当然我觉得也可以使用Command模式,
或者ATL机制的消息映射表,比MFC的更有效率,而且更适用:)
Reply all
Reply to author
Forward
0 new messages