while(true)ServerSocket Listen的效率
我想知道一个典型的while(true)
ServerSocket监听循环是否需要整个核心等待并接受客户端连接(即使实现runnable并使用Thread .start()
)
我正在实现一种分布式计算集群,每台计算机都需要它用于计算的每个核心。 主节点需要与这些计算机通信(调用修改算法function的静态方法)。
我需要使用套接字的原因是由于跨平台/跨语言function。 在某些情况下,PHP将调用这些java静态方法。
我使用了一个java profiler(YourKit),我可以看到我正在运行的ServerSocket监听线程,它永远不会睡觉而且它总是在运行。 有没有更好的方法来做我想要的? 或者,性能影响是否可以忽略不计?
如果你能想到一个更好的方法,请随时提供任何建议(我已尝试过RMI,但不支持跨语言。
感谢大家
如果你的意思是这样的:
while (true) { Socket socket = server.accept(); /* Do something with socket... */ }
然后,不,对accept()
的调用不会“占据整个核心”。 这是一个阻塞调用,允许在另一个线程上调度CPU,直到客户端实际连接为止。 一旦对accept()
的调用返回,当前线程将被调度为运行并将消耗CPU,直到它在循环的下一次迭代中阻塞在accept()
上。
为了避免其他客户端的监听积压过大,另一个线程通常会处理与新接受的Socket
交互,让一个线程专注于接受新客户端。 套接字处理线程可能使用NIO处理许多套接字,或者它可能专用于单个套接字,这对于编码来说要简单得多,但在数百个并发连接之后不能很好地扩展。
您可能希望查看Java 1.4 nio库,特别是ServerSocketChannel。 我非常成功地使用它来实现一个高效的服务器,代码的关键部分是:
Selector selector = Selector.open(); ServerSocketChannel server= ServerSocketChannel.open(); server.socket().bind(new java.net.InetSocketAddress(port)); server.configureBlocking(false); SelectionKey serverKey = server.register(selector, SelectionKey.OP_ACCEPT); // start listening thread new Thread(listener).start();
并且监听器只是一个运行的循环:
selector.select(1000); // listen for one second max Set keys = selector.selectedKeys(); if (keys.size()>0) { handleKeys(keys); }
我使用了一个java profiler(YourKit),我可以看到我正在运行的ServerSocket监听线程,它永远不会睡觉而且它总是在运行。
基本上,分析器会误导你。
我假设您的代码如下所示:
ServerSocket server = ... // configure server socket try { while (true) { Socket socket = server.accept(); // do something with socket (and close it afterwards!) } } catch (InterruptedException ex) { // we're outta here! }
这不会占用大量的CPU …除非你做了一些病态的事情,比如用一个小的超时调用ServerSocket.setSoTimeout(int)
。
让核心睡一会儿。 在Runnable方法中,添加类似的内容
Thread.sleep(250); // milliseconds
在每个循环中。
这应该会显着降低CPU使用率
编辑:坏主意,看评论,对不起,我的错
并且:不要使用while(true)。 这是一个糟糕的设计,因为语义表明最终真实不再是真实的。 通常,您需要从主线程查询一些volatile或primefaces变量
public class MyClass { class MyRunnable implements Runnable { public void run() { while (MyClass.this.keepGoing.get()) { // listen(); try { Thread.sleep(500); } catch (InterruptedException e) { // deal with exception } } } } private final AtomicBoolean keepGoing = new AtomicBoolean(true); }
这样主线程就有办法停止监听器线程。