伟大的DCOM解决方案

来源:互联网 发布:戚风蛋糕的做法 知乎 编辑:程序博客网 时间:2024/04/28 17:08


MS的COM以及其后提供分布式对象支持的DCOM/COM+技术现在仍然被广泛使用,不过官方说法它的未来应该是.Net,.Net有多好我不知道,DCOM有多烂到时略知一二,特别是对应Visual Basic的实现。

 COM的前身是OLE,主要用于解决Office多文档之间的协作,OLE本身及其复杂,有部分是本质复杂性的原因。总的来说还可以接受。

不过其后为了给COM增加位置透明以及运用在后台组件的开发上,MS使用了DCE RPC协议,扩展了COM。
DCOM本身的原型很简单,一个RPC机制,但是由于某些MS产品的本质技术特性,扭曲了它的实现,某些特指Visual Basic和MFC。

Visual Basic,包括MFC都是具有线程亲缘性的,什么是线程亲缘性呢?
举个例子:
 我有一个class A,A中有一个方法foo(),


class A
{
  void foo(){ ... }
};

如果有N个线程T1....Tn,
我在T1线程中调用  A a = new A;
然后运行 a->foo() 这句本身是没有任何问题的。

但是由于我们是多线程程序,假设现在的T2线程来了,我给这个T2线程以a的指针,然后在T2线程中,我想调用 a->foo() 应该也没有问题,即使Class A的foo本身没有提供线程保护机制,只要保证其他的线程T1,T3...Tn在该时刻不同时调用foo就应该可以。对吗?

可惜不对,在DCOM模型中,由于Visual Basic具有线程亲缘性,a这个对象是在T1线程中被创建,那么该对象就和T1线程绑定在一起,所有的方法调用必须只能在T1线程中运行。(这也是为什么T1线程需要一个消息循环的原因,因为T2线程在调用a的foo方法的时候,要调用T1的SendThreadMessage,然后经过线程切换,在T1的线程环境中运行,然后再次切换到T2线程,得到调用结果)。

这会导致一个什么情况呢?打个比方,假设你在某某银行办了一个新的银行账号(对应new了一个component),银行柜台有10个窗口(对应你的服务有10个线程),下次你准备存取款的时候(对应需要对该component进行方法调用),发现银行前面有一个这样的告示:本银行系统已经通过了apartment国际认证(对应该compoment使用了DCOM的apartment线程模型),请客户在办理业务的时候,去开户的那个特定窗口排队等候。多谢合作!

你发现这天所有的排队等候者(对应一些DCOM对象的实例)都是在1号窗口开的户(对应都是在T1线程中被创建的),你好彩也是如此,结果你就排在1号窗口的长龙后面,等待你的时间片。而其他9个窗口几乎没有什么人。你眼巴巴的看着后来的那些非1号窗口的取款者轻轻松松地办完了他们的业务,离开的时候还以一种疑惑的眼神瞟了你几眼。你是不是觉得自己像个SB,无限郁闷,火气大的可能都想@#@##@¥了,对吧?

当然该银行也提供了几个解决方法,期待吧?

你从银行的Bank Guide 杂志发现了几个解决方案,一种是银行内部实现的,它购买了旁边的一块地皮,将银行柜台数目扩展到100个(对应最初MTS中默认的100个线程),期望通过随机原理能够缩短你的等待时间。但是你发现银行开始收手续费了,因此这块地,这些窗口后面的工作人员可不都是免费的(对应你系统中由于线程切换,调度引起的资源消耗)。

Band Guide杂志介绍的另外一种方法更加有效,简直爽得你死去活来。就是建议你每次去银行,你都是重新开户(new),然后办理业务(invoke),最后注销账号(delete), 对应刚才我说的“死去活来”(你应该知道VB写的compoment是不能使用DCOM的Pool的,对吧?)。银行的解释是:这样可以减轻我们账号数据库的负担(对应内存的使用)。你现在觉得好像不仅仅你,也包括这家银行,都属于BT级的弱智,对吧?这就是DCOM的apartment线程模型世界。

那么具体有多少这样的银行呢?我估计大概80%可能都是如此。因为据说VB的开发人员超过VC的10倍,你就可以想像有多少业务层组件是使用VB开发的。前面说了,由于Visual Basic的runtime具有线程亲缘性,因此所有VB开发的Component都是如此,因此也就能大概估计有多少组件是通过了Apartment国际认证的。

多么伟大的solution啊!