Java中UDP DatagramSocket线程的高CPU使用率
我正在运行一个多线程java服务器应用程序,其中包括在3个不同线程上从3个不同的多播源(端口)接收UDP数据包 它运行在最近的双插槽redhat box上(共有8个内核(4 x 2 cpu),没有超线程) “top”命令显示cpu使用率为250~300%。 shift-H显示2个线程的使用率约为99%,1个线程的使用率为70%。快速线程jstack分析显示,这些线程与我的UDP处理线程相对应 考虑到CPU速度与UDP消息速率(大约300 msg/秒,对于大约250字节的有效负载),CPU使用率的水平让我有点惊讶,我正在对此进行研究。值得注意的是,第三个线程(对应于较低的cpu使用率)具有较低的数据速率(50~100 msg/s) 我已经包含了一些调试代码来衡量大部分时间花在哪里,它似乎在DatagramSocket的“receive()”方法中:Java中UDP DatagramSocket线程的高CPU使用率,java,multithreading,sockets,udp,cpu-usage,Java,Multithreading,Sockets,Udp,Cpu Usage,我正在运行一个多线程java服务器应用程序,其中包括在3个不同线程上从3个不同的多播源(端口)接收UDP数据包 它运行在最近的双插槽redhat box上(共有8个内核(4 x 2 cpu),没有超线程) “top”命令显示cpu使用率为250~300%。 shift-H显示2个线程的使用率约为99%,1个线程的使用率为70%。快速线程jstack分析显示,这些线程与我的UDP处理线程相对应 考虑到CPU速度与UDP消息速率(大约300 msg/秒,对于大约250字节的有效负载),CPU使用率的
_running = true;
_buf = new byte[300];
_packet = new DatagramPacket(_buf, _buf.length);
while(_running) {
try {
long t0 = System.nanoTime();
_inSocket.receive(_packet);
long t1 = System.nanoTime();
this.handle(_packet);
long t2 = System.nanoTime();
long waitingAndReceiveTime = t1-t0;
long handleTime = t2-t1;
_logger.info("{} : {} : update : {} : {}", t1, _port, waitingAndReceiveTime, handleTime);
}
catch(Exception e) {
_logger.error("Exception while receiving multicast packet", e);
}
}
handleTime的平均值为4000ns,这是非常快的,不能对CPU的使用负责。
waitingAndReceiveTime要高得多,从30000ns到几毫秒。我知道方法是阻塞的,所以时间包括阻塞时间和接收时间
我有几个问题:
- UPD消息确实以10个一组的形式出现:对于每个组,第一条消息的等待和接收时间都很长(>=1ms),而下面的9条等待和接收时间要短得多(~2000ns)。(handleTime相同)
- CPU使用率降低!对于前两个线程,下降到大约55%
仍然不知道如何解决这个问题这不是一个真正的答案,但: 有一件事我可以向你保证,那不是Java代码。我用Python做了一个多线程UDP服务器,它也做了同样的事情,CPU使用率在3到4秒内跃升到100%。 我猜这真的和UDP本身有关,因为我还制作了一个多线程TCP服务器,它的CPU使用率仅为10% 代码如下:
import socket
from _thread import*
import threading
import time
def threaded(s,serverIP,serverPort):
while True:
try:
d = s.recvfrom(128)
data = d[0]
addr = d[1]
message= str(data)
if (message== "b'1'"):
time.sleep(5)
s.sendto(str.encode(message) , addr)
print(message)
except:
break
s.close()
def Main():
serverPort = 11000
serverIP= "127.0.0.1"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((serverIP, serverPort))
while True:
start_new_thread(threaded, (s,serverIP,serverPort))
s.close)
if __name__ == '__main__':
Main()
注:
如果你找到了答案,请告诉我。
祝你好运。这是什么。handle做什么?它对数据包进行简单的处理:基本上解析字符串,并进行一些计算-没有什么太大的负担,正如averagetry profiling 1上花费的4000ns时间所示。你怀疑有些事情很奇怪是对的。2.是的,
receive()
正在阻塞,因此它不可能占用100%的CPU。4.我怀疑不是Java代码负责(所有)使用,而是本机代码(或一些被忽略的重要Java代码)。。。