我有一个应用程序,需要控制许多从属进程来完成任务。并且有一个匹配的线程来完成匹配工作。我使用EventWaitHandle在它们之间进行通信,在空闲时间匹配的线程等待slave的事件,代码如下:
EventWaitHandle.WaitAny(GetWaitEvents());
//GetWaitEvents method will return all slave process's EventWaitHandle
在奴隶过程中,一旦它是免费的。它将触发事件以将另一个任务与此过程相匹配。代码如:
ProxyEvent.Set()
但是,当事件的数量超过64时,它将抛出System.NotSupportedException。 检查代码来自Microsoft后,我发现它是framwork代码中的硬代码:
private const int MAX_WAITHANDLES = 64;
我的问题是:
答案 0 :(得分:3)
为什么?一旦你意识到它是从WaitForMultipleObjects
继承的,就可以很容易地回答。反过来,它有一个限制,因为函数的返回值试图将多个事实编码为一个整数,因此他们选择了一个适用于大多数情况的实用值。
我同意@ Pako的评论 - 很可能运行(超过)64个线程可能不是最好的方法 - 如果它们都是活动的并且你的内核少于64个,你很可能当它可以执行有用的工作时,淹没系统及其浪费时间执行上下文切换。
使用例如Task
或TPL将允许您的代码按照实际可以执行的工作量进行优雅扩展。
答案 1 :(得分:2)
64的原因是64位处理器上字的位数。
该实现使用位标志使其尽可能快。
变通方法根据您的目的而有所不同。例如,参见V4Vendetta提到的Workaround for the WaitHandle.WaitAll 64 handle limit?。
我使用的一种解决方法是创建将等待句柄拆分为两个数组,然后使用一个线程等待其中一个数组,另一个线程等待另一个数组。然后主线程等待这些线程中的任何一个。这不是很好,因为它使用了一个额外的线程。
(我的实际实现比上面的解释更复杂。我必须在每个数组中将等待句柄的数量限制为63,因为我需要额外的一个来阻止“其他”线程等待其中一个完成了等待阵列。)
WaitForMultipleObjects()
的MSDN文档确实提到了几个解决方法:
创建一个线程以等待MAXIMUM_WAIT_OBJECTS句柄,然后等待该线程加上其他句柄。使用此技术将句柄分成MAXIMUM_WAIT_OBJECTS组。
调用RegisterWaitForSingleObject在每个句柄上等待。来自线程池的等待线程在MAXIMUM_WAIT_OBJECTS注册的对象上等待,并在发出对象信号或超时间隔到期后分配工作线程。
(我过去使用过第一种方法,但我早就改写了代码来改用IO完成端口。)