Java中的UDP Datagramsocket线程上的高CPU使用率



我正在运行一个多线程Java服务器应用程序,除其他外,该应用程序正在从3个不同的线程上接收来自3个不同的多播源(端口(的UDP数据包。

它在最近的双插入式雷达盒(总计8个内核(4 x 2 CPU(,没有超线程(上运行。

" top"命令以250〜300%的形式显示CPU使用率。Shift-H显示了2个螺纹,约为99%的使用率,为70%。快速线程JSTACK分析显示这些线程对应于我的UDP处理线程。

考虑到CPU速度与UDP消息速率(约300毫克/秒钟,有效载荷约250个字节(,我对CPU使用级别的水平感到有些惊讶,我正在调查此问题。有趣的是,第三个线程(对应于较低的CPU使用率(的数据速率较低(50〜100 msg/s(

我包括了一些调试代码来测量大多数时间的花费,并且它似乎在datagramsocket的" recection(("方法中:

_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);
    }
}

平均为4000NS的平均值,这非常快,不对CPU使用负责。从大约30,000ns到几个MS,等待和序列时间要高得多。我知道该方法正在阻止,因此时间包括时间阻止和接收时间。

我有几个问题:

  1. 我怀疑某事很奇怪吗?
  2. 我认为"接收(("正在阻止,它不应"浪费" CPU周期,因此等待部分不应对高CPU使用负责,对吗?
  3. 是否有一种方法可以将时间阻止的测量以及接收方法接收到数据报的时间?
  4. 什么可能负责此高CPU使用?

edit :我使用中断合并参数,将Rx-usecs放在0,然后将Rx-Frames放在10中。我现在可以看到以下内容:

  • UPD消息确实出现在10组中:对于每个组,第一个消息的等待时间很长(> = 1ms(,并且以下9个weateandReceivEtime较短(〜2000NS(。(手点是相同的(
  • CPU使用率减少了!对于2个第一个线程,下降到约55%。

仍然不知道如何解决此

不是真正的答案,而是:

我可以向您保证的一件事,这不是Java代码。我在Python中做了一个多线程UDP服务器,并且它做同样的事情,CPU使用率在3到4秒内跳至100%。我猜这确实与UDP本身有关,因为我还制作了多线Readed 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()

注意:

如果找到答案,请告诉我。祝你好运。

我已经在这个问题上击败了自己11年了。我写了一个家庭自动化应用程序,该应用使用UDP与单个房间控制器进行交谈。无论我做什么,它都会浪费完整的处理器核心(100%处理器使用情况(,以接收UDP数据报。我去了进行了完整的调查,看来这正是UDP接收的方式在Java中实现。从那以后,我已经更新了Java Untold Times(实际上已经11年了(,最近也将其从PC迁移到Raspberry Pi4。即使在Raspberry上,它仍然使用一个整个核心来接收UDP数据包...这可能是一个简单的错误,这些年来一直未被发现,或者也许有一个原因为什么您无法更有效地收到UDP数据包。我不是一个合适的开发人员,所以我不敢向Oracle发布适当的错误报告。

最新更新