我想知道,在java 1.6 x64中让许多线程处于等待状态是多么昂贵。
更具体地说,我正在编写运行在多台计算机上并从一台计算机发送/接收数据的应用程序。我觉得为每台连接的机器和任务分别设置单独的线程感觉更舒服,例如1)发送数据,2)接收数据,3)删除时重新建立连接。因此,假设集群中有N个节点,则每台机器将为N-1个邻居中的每个节点设置3个线程。通常会有12台机器,来自33个通信线程。
这些线程中的大多数都会在大多数时间处于休眠状态,因此出于优化目的,我可以减少线程数并为每个线程提供更多工作。比如,例如。重新建立连接是接收线程的责任。或者通过单线程发送到所有连接的机器。
那么,对于拥有许多睡眠线程有什么显着的性能影响吗?
答案 0 :(得分:15)
对于大多数情况,睡眠线程消耗的资源将是其堆栈空间。我认为使用每个连接2个线程的模型与您所描述的类似,当连接数量变大时,会出现这种原因造成很大的可伸缩性问题。
我自己一直处于这种情况,当连接数增加到超过500个连接(大约一千个线程)时,你会遇到许多情况,你会得到OutOfMemoryError,因为线程堆栈空间使用超过了单个进程的最大内存量。至少在我们的情况下,这是在32位Windows世界的Java中。我猜你可以调整一些东西并进一步调整,但最后由于你浪费了大量内存,它的可扩展性不高。
如果您需要大量连接,Java NIO(新IO或其他)是可行的方法,可以在同一个线程中处理大量连接。
话虽如此,在合理的现代服务器上,你不应该遇到100个线程的问题,即使它可能仍然是浪费资源。
答案 1 :(得分:2)
在我们切换到NIO之前,我们遇到了同样的问题,因此我将推荐Liedmans推荐使用该框架。你应该能够找到一个教程,但是如果你想要详细信息,我可以推荐Ron Hitchens的Java NIO。
切换到NIO增加了我们可以处理的连接数量,这对我们来说非常关键。
答案 2 :(得分:1)
这不会很好地扩展。拥有大量线程意味着VM必须花费更多时间进行上下文切换,并且由于每个线程需要自己的堆栈空间,因此内存使用率会更高。使用较少数量的线程以流水线方式处理会更好,或者使用线程池和异步技术。
答案 3 :(得分:1)
许多线程等同于大量的堆栈空间,这将耗尽你的记忆 - 检查你的-Xss设置是多少,然后做数学。
如果由于某种原因你不得不做一个notifyAll(),那么当然你正在唤醒大量的额外线程 - 尽管你可能不需要在你提出的架构中这样做。
我不确定你能否轻松避免在这个模型中每个侦听套接字都有一个线程(虽然我对NIO知之甚少 - 这可能解决了这个问题),但是看看java.util.concurrent.Executor接口和它的实现类以一种体面的方式避免过多的额外线程。实际上,ThreadPoolExecutor
也可能是管理监听线程的好方法,因此您不必花费太多时间来创建和销毁线程。
答案 4 :(得分:0)
从我在C,Lua和Python中完成的测试中,您可以使用非常少的代码行进行自己的睡眠或等待功能,以创建一个简单的轻量级循环。 使用一个局部变量和您想要到达的未来时间,然后在while循环中测试当前时间戳。如果您在使用fps的作用域中,请使每帧运行一次wait函数以节省资源。 您需要的精度越高,请考虑使用时钟而不是时间戳,因为时间戳限制为秒。 您添加到等待函数中的代码行越多,它变得越精确,消耗的资源就越多,尽管10行以下的任何内容都应该足够快。