找回密码
 用户注册

QQ登录

只需一步,快速开始

楼主: iq50

关于ACE_WIN32_Proactor代码的一些疑惑

[复制链接]
发表于 2009-6-17 13:13:13 | 显示全部楼层
查了下书。确认ACE_WIN32_Proactor
1)是可以多线程跑event loop的
第8.5节:
Concurrency considerations. Multiple threads can execute the event loop of an ACE_WIN32_Proactor simultaneously. Since all event registration and dispatching is handled by the I/O completion port mechanism, and not by the ACE_WIN32_Proactor itself, there's no need to synchronize access to registration-related data structures, as in the ACE_WFMO_Reactor implementation (page 106).
但是后面也提到timer event要注意只能在某一个固定线程中处理。
2)也可以单线程。
8.5节的sidebar说的就是在一个线程里跑reactor+proactor

下面说下我个人的理解:
除了不适合多线程的情况外(如上面说的reactor+proactor,因为多线程reactor要考虑同步),是否多线程,用多少个线程,是出于性能考虑。
仔细看了下windows网络编程。其中提到CreateIoCompletionPort function的第四个NumberOfConcurrentThreads(就是执行event loop的线程)其值一般对应主机的cpu数目。
书中提到了worker thread,就是我们设定的跑event loop的线程。这个数目和NumberOfConcurrentThreads的区别在于,NumberOfConcurrentThreads指物理并发数,worker thread指逻辑并发数。worker thread数目常常大于NumberOfConcurrentThreads。但是如果确定worker thread不会“calls a function—such as Sleep or WaitForSingleObject—and becomes suspended”,这两个数目可以相等。

详文:

It's important to note the distinction between number of concurrent threads to specify when calling CreateIoCompletionPort versus the number of worker threads to create; they do not represent the same thing. We recommended previously that you should have the CreateIoCompletionPort function specify one thread per processor to avoid thread context switching. The NumberOfConcurrentThreads parameter of CreateIoCompletionPort explicitly tells the system to allow only n threads to operate at a time on the completion port. If you create more than n worker threads on the completion port, only n threads will be allowed to operate at a time. (Actually, the system might exceed this value for a short amount of time, but the system will quickly bring it down to the value you specify in CreateIoCompletionPort.) You might be wondering why you would create more worker threads than the number specified by the CreateIoCompletionPort call. As we mentioned previously, this depends on the overall design of your application. If one of your worker threads calls a function—such as Sleep or WaitForSingleObject—and becomes suspended, another thread will be allowed to operate in its place. In other words, you always want to have as many threads available for execution as the number of threads you allow to execute in the CreateIoCompletionPort call. Thus, if you expect your worker thread to ever become blocked, it is reasonable to create more worker threads than the value specified in CreateIoCompletionPort's NumberOfConcurrentThreads parameter.
发表于 2009-6-17 13:14:10 | 显示全部楼层
以上理解是否有问题,请winston老大和modern来指正。
发表于 2009-6-17 13:21:09 | 显示全部楼层
原帖由 modern 于 2009-6-16 18:02 发表
最近有点职业病,我刚在思考一个问题,如何通过测试数据来说明这个问题。
思考之后,我认为如果要得出这个值可能受限于很多实际应用情况。

换言之,可能即便在这一步,使用多线程运行proactor性能被提升了,
系统的整体处理性能 ...

以前做过一段时间的系统工程师,性能测试压力测试是主要工作内容之一。
我的经验是,测试一个特定问题,测试计划要尽量屏蔽掉其他可能造成影响的因素。
如有必要多做几个原理相异的测试方案,从多方印证所得出的结论。
发表于 2009-6-17 14:28:42 | 显示全部楼层
原帖由 wishel 于 2009-6-17 13:13 发表
查了下书。确认ACE_WIN32_Proactor
1)是可以多线程跑event loop的
第8.5节:
Concurrency considerations. Multiple threads can execute the event loop of an ACE_WIN32_Proactor simultaneously. Since all event re ...

你看的材料,我都看过,是这样的。ACE只不过是API的封装,我们得理解API背后的深层含义。
发表于 2009-6-17 14:32:48 | 显示全部楼层
和我理解的基本一致。

不过timer event貌似因为使用的是PostQueuedCompletionStatus,
而非通用的GetQueuedCompletionStatus。
因此proactor已经确保只有一个线程会处理定时器事件。
这个无须使用者,另行操心。

he timer queue expiry management is handled in a separate thread that's managed by the ACE_WIN32_Proactor. When a timer expires, the timeout mechanism uses the PostQueuedCompletionStatus() function to post a completion to the proactor's I/O completion port. This design cleanly integrates the timer mechanism with the normal completion dispatching mechanism. It also ensures that only one thread is awakened to dispatch the timer since all completion-detection threads wait only for completion events and needn't worry about waking up for a scheduled timer expiration.
发表于 2009-6-17 14:54:09 | 显示全部楼层
原帖由 modern 于 2009-6-17 14:32 发表
和我理解的基本一致。

不过timer event貌似因为使用的是PostQueuedCompletionStatus,
而非通用的GetQueuedCompletionStatus。
因此proactor已经确保只有一个线程会处理定时器事件。
这个无须使用者,另行操心。

he ti ...



这段好像是说timer事件会(随机)唤醒一个线程来处理。
但是我跑过一个例子,好像这个线程是固定指定的,不是随机选择的。
假如在程序里故意让这个线程(找到线程id)去忙别的事情,没机会运行event loop,那么timer事件就不会得到处理,虽然有其他线程在跑event loop。

[ 本帖最后由 wishel 于 2009-6-17 14:57 编辑 ]
发表于 2009-6-17 15:01:04 | 显示全部楼层
he timer queue expiry management is handled in a separate thread .
在一个单独的线程中处理定时器队列超时的管理问题

如果我没翻译错的话、、、
你测试的例子反映的应该是实际情况吧
发表于 2009-6-17 15:15:27 | 显示全部楼层
我查了一下源代码,
我想这段的意思应该是这样的。
启动ACE_Proactor之后在构造函数的时候激活的一个专门调度定时器的线程(ACE_Proactor_Timer_Handler),我们运行事件循环的线程只是负责,调用GetQueuedCompletionStatus,获得已经完成的异步信息,并进行处理。
在定时器发生超时事件的时候之后,ACE_Proactor_Timer_Handler启动的这个线程,会通过PostQueuedCompletionStatus给完成端口发送一个完成的消息,然后运行事件的循环的线程检查到有异步事件完成,取出来,则自动会处理了,然后我们配置的handle_time_out就会被调用了。
这个ACE_Proactor_Timer_Handler由proactor封装起来,貌似没有提供对外操作的接口,
因此我们也没有机会故意阻塞他,所以定时器事件会被proactor很好的被调度。

[ 本帖最后由 modern 于 2009-6-17 15:21 编辑 ]
发表于 2009-6-17 15:20:36 | 显示全部楼层
原帖由 modern 于 2009-6-17 15:01 发表
he timer queue expiry management is handled in a separate thread .
在一个单独的线程中处理定时器队列超时的管理问题

如果我没翻译错的话、、、
你测试的例子反映的应该是实际情况吧 ...

之前没注意到separate这个词。

那么在用多线程proactor处理timer和其他event混合的情况的时候,还是要注意一下,有一个特殊线程与其他线程并不是完全平等的。
发表于 2009-6-17 15:26:20 | 显示全部楼层
原帖由 modern 于 2009-6-17 15:15 发表
我查了一下源代码,
我想这段的意思应该是这样的。
启动ACE_Proactor之后在构造函数的时候激活的一个专门调度定时器的线程(ACE_Proactor_Timer_Handler),我们运行事件循环的线程只是负责,调用GetQueuedCompletionStatus,获 ...

你的意思是,运行timer事件对应handler的线程,并不属于worker thread,而是系统另外产生的?
我晚上回去看看以前跑的那个例子程序。
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-12-23 17:53 , Processed in 0.018535 second(s), 4 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表