Java socket侦听器100%的CPU负载
我需要不断地侦听远程套接字并对给定的输入做出反应。Java socket侦听器100%的CPU负载
public void listen(String ip, int port) {
try (
Socket socketListener = new Socket(ip, port);
BufferedReader portReader = new BufferedReader(new InputStreamReader(socketListener.getInputStream()));
) {
while (true) {
while (!portReader.ready()) {
// Wait for next PORT message
}
Logger.log(LogComponent.SOCKET, "Event received");
}
}
}
我在做什么这么大的错误,以上代码使用100%的CPU负载?
在调试时我可以看到while-!portreader-loop是恶作剧者。但是我发现的大多数例子都是这样做的。
编辑#1
考虑您的意见,我有如下的解决方案现在:
try {
Socket SocketListener = new Socket(ip, port);
BufferedReader portReader =
new BufferedReader(
new InputStreamReader(SocketListener.getInputStream())
);
// We do not use common while(true)-pattern for reading the input.
// Instead, we check for new input 3 times a second.
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
executor.scheduleAtFixedRate(() -> {
try {
processInput(portReader);
} catch (IOException e) {
e.printStackTrace();
}
}, 0, 333, TimeUnit.MILLISECONDS);
} catch (Exception exception) {
exception.printStackTrace();
}
而且processInput(0)
现在正在做的动作。 这结束比使用Thread.sleep()更好的性能结果 - 虽然我不明白为什么。
使用此方法时:代码是否可能会遗漏来自套接字的某些消息?我的意思是在间隔期间?
问题是,你的代码在你的while(true)中占用了所有的CPU。作出这样一个变化:因为它的处理在while
循环指令
public void listen(String ip, int port) {
try (Socket socketListener = new Socket(ip, port);
BufferedReader portReader = new BufferedReader(new InputStreamReader(socketListener.getInputStream()));) {
while (true) {
while (!portReader.ready()) {
// Wait for next PORT message
try {
Thread.sleep(1);
} catch(InterruptedException e) {
//handle InterruptedException
}
}
Logger.log(LogComponent.SOCKET, "Event received");
}
}
}
由于只有在服务器发送数据时,portReader.ready()才为真,因此indle时CPU消耗相同。 –
你的CPU是繁忙的。
要避免它,你应该使用一个等待插座连接的函数。如果您正在等待传入连接,请使用Socket.accept()
。这将阻塞线程(即线程不会被调度执行)直到连接建立。
不要像其他人所建议的那样使用Thread.sleep()
。虽然这确实降低了CPU使用率,但它仍会不必要地烧毁CPU,并引入延迟。这是一个糟糕的工程实践。
除此之外,您可能需要查看非阻塞或异步I/O。 See here了解更多信息。
'while true'将始终以CPU允许的速度运行。因此需要一个“延迟”来减慢你的循环。计算每秒要检查远程套接字的频率并插入适当的延迟。例如,等待1/10秒将导致每秒约10次检查(减去检查时间)。 –
您还需要提供一个标记消息结束的字节。您的代码被设计为读取的方式永远不会返回-1,您将不得不关闭流以实现此目的。 – MissingSemiColon
为什么你不能只执行阻塞阅读?使用'Reader.ready()'来测试可读性是一个错误的设计。如果您需要非阻塞行为,请考虑使用SelectableChannel或Java 7中引入的异步I/O功能。 –