Delphi XE4 + Indy TCP服务器:线程数大



Windows服务有多个永久TCP连接,接受数据,在单独的线程中处理,定期向所有连接的客户端发送更新。处理必须尽可能实时地完成,客户端每2-4秒发送一条消息。

在处理1900个连接时,服务大约有1970个线程。直到现在都很好。但是,当线程总数超过2000-2200时,事情就变得奇怪了——有时处理线程会无缘无故地阻塞10秒,即使使用实时优先级也是如此。在10秒内,进入队列的请求就会被成千上万的请求填满,所以即使是一秒钟的延迟也是不可接受的。尝试使用TSchedulerOfThread来限制线程数,但实际上这只限制了连接数…

我知道Indy每个TCP连接消耗一个线程。所以我测试了Overbyte ICS,它使用windows消息传递(我不太喜欢这个,但也没有别的选择)。线程计数显著降低(仍然70,但是没关系),工作细也与3000联系。几个小时后,服务在没有调用堆栈的情况下随机崩溃(madExcept正在使用)。在windows事件日志中只有一条记录被标记为"应用程序崩溃"。

所以Indy和ICS都不适合我。

中间有解决方案吗?我可以使用1000个线程,但不能使用3000个…

根据注释中的附加信息,最有可能的问题来自您的工作线程的Sleep(),Sleep()的文档:

在休眠间隔过去后,线程准备运行。如果指定0毫秒,则线程将放弃剩余的时间片,但仍保持就绪状态。请注意,一个就绪的线程不能保证立即运行。

我认为Windows中的线程调度器不能很好地处理这么多线程,而且很可能在您的Sleep(5)之后,Windows仍然忙于在其他线程之间切换。此外,如果您每秒接收1000条消息,即使5毫秒的睡眠时间也很长。

在这种情况下,我们总是使用TThreadedQueue(不确定它是否在您的Delphi版本中可用)和PushItem()/PopItem()用于生产者/消费者数据传输。你不需要让线程进入睡眠状态,因为"PopItem()waits for a new message to arrive in the queue (it uses internal logic with aTMonitor ' sync)。我们的工作线程是这样的:

while not Terminated do
begin
FMsg := MsgQueue.PopItem;  //ThreadQueue waits (for PopTimeout) here for item to appears
if Assigned(FMsg) then
begin
AddLogDebug('Begin DoProcessMsg');
DoProcessMsg;
AddLogDebug('End DoProcessMsg');
end;
end;

最新更新