我想知道,在 java 1.6 x64 中让许多线程处于等待状态的成本有多大。

更具体地说,我正在编写一个在多台计算机上运行并从一台计算机到另一台计算机发送/接收数据的应用程序。我觉得为每个连接的机器和任务拥有单独的线程更舒服,例如 1) 发送数据,2) 接收数据,3) 在连接断开时重新建立连接。因此,假设集群中有 N 个节点,每台机器将为 N-1 个邻居中的每一个拥有 3 个线程。通常会有 12 台机器,即 33 个通信线程。

大多数线程大部分时间都会处于休眠状态,因此出于优化目的,我可以减少线程数量并为每个线程提供更多工作。比如说。重新建立连接是接收线程的责任。或者发送到所有连接的机器是通过单线程完成的。

那么拥有许多休眠线程对性能有什么重大影响吗?

有帮助吗?

解决方案

在大多数情况下,休眠线程消耗的资源将是其堆栈空间。我认为使用每个连接 2 线程的模型与您所描述的类似,众所周知,当连接数量变大时,会导致巨大的可扩展性问题。

我自己也遇到过这种情况,当连接数超过 500 个连接(大约一千个线程)时,您往往会遇到很多出现 OutOfMemoryError 的情况,因为线程堆栈空间使用量超过了最大数量单个进程的内存。至少在我们的例子中,这是在 32 位 Windows 世界上的 Java。我猜你可以调整一些东西并进一步发展,但最终它的可扩展性不太好,因为你浪费了大量的内存。

如果您需要大量连接,Java NIO(新 IO 或其他)是最佳选择,它可以在同一线程中处理大量连接。

话虽如此,在相当现代的服务器上,如果线程数少于 100 个,您不应该遇到太大的问题,即使这可能仍然浪费资源。

其他提示

在转向 NIO 之前,我们遇到了非常相似的问题,所以我会赞同 Liedman 的建议,选择使用该框架。您应该能够找到教程,但如果您想要详细信息,我可以推荐 Java NIO 作者:罗恩·希钦斯。

改用 NIO 增加了我们可以处理的连接数量,这对我们来说非常重要。

这不会很好地扩展。拥有大量线程意味着虚拟机必须花费更多时间进行上下文切换,并且由于每个线程都需要自己的堆栈空间,因此内存使用率会更高。您最好以管道方式处理较少数量的线程,或者使用具有异步技术的线程池。

许多线程相当于大量堆栈空间,这会消耗您的内存 - 检查您的 -Xss 设置以了解多少,然后进行数学计算。

如果您出于某种原因必须执行notifyAll(),那么您当然会唤醒大量额外的线程——尽管您可能不需要在建议的体系结构中这样做。

我不确定您是否可以轻松地避免在此模型中每个侦听套接字有一个线程(尽管我对 NIO 知之甚少 - 这甚至可能解决该问题),但是请看一下 java.util.concurrent.Executor 接口及其实现类提供了一种避免过多额外线程挂起的好方法。确实, ThreadPoolExecutor 也可能是管理侦听线程的好方法,因此您不会花费太多时间创建和销毁不必要的线程。

根据我在 C、Lua 和 Python 中所做的测试,您可以使用很少的代码行来创建自己的睡眠或等待函数,以创建一个简单的轻量级循环。将局部变量与您想要达到的未来时间一起使用,然后在 while 循环中测试当前时间戳。如果您处于使用 fps 的范围内,请让等待函数每帧运行一次以节省资源。您需要的精度越高,请考虑使用时钟而不是时间戳,因为时间戳仅限于秒。添加到等待函数中的代码行越多,它的精确度就越低,消耗的资源也就越多,尽管 10 行以下的代码应该足够快。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top