@Roddy - 我已经阅读了您指向的链接,它们都引用自 Paul Tyma 的演示文稿“数千个线程和阻塞 I/O - 编写 Java 服务器的旧方法又是新的”。
然而,Paul 的演示中不一定会跳出来的一些事情是,他在启动时为 JVM 指定了 -Xss:48k,并且他假设 JVM 的 NIO 实现是高效的,以便它是有效的比较。
Indy没有指定类似的缩小和严格限制的堆栈大小。Indy 代码库中没有调用 BeginThread(Delphi RTL 线程创建例程,您应该在这种情况下使用)或 CreateThread(原始 WinAPI 调用)。
默认堆栈大小存储在 PE 中,对于 Delphi 编译器,它默认为 1MB 的保留地址空间(空间由操作系统以 4K 块逐页提交;实际上,编译器需要生成触摸页面的代码,如果函数中有 >4K 的局部变量,因为扩展由页面错误控制,但仅适用于堆栈中的最低(保护)页面)。这意味着在最多 2,000 个并发线程处理连接之后,您将用完地址空间。
现在,您可以使用 {$M minStackSize [,maxStackSize]} 指令更改 PE 中的默认堆栈大小,但这会影响所有线程,包括主线程。我希望你不要做太多的递归,因为 48K 或(类似的)空间并不大。
现在,Paul 对于 Windows 异步 I/O 的非性能是否正确,我不能 100% 确定——我必须对其进行测量才能确定。然而,我所知道的是,关于线程编程比基于事件的异步编程更容易的论点正在呈现一种错误的二分法。
异步代码不需要基于事件;它可以是基于延续的,就像在 .NET 中一样,如果你指定一个闭包作为你的延续,你可以免费为你维护状态。此外,从线性线程式代码到连续传递式异步代码的转换可以通过编译器进行机械化(CPS 转换是机械式的),因此代码清晰度也不需要任何成本。