1

次のコード スニペットを取得します。

datagramChannel = DatagramChannel
    .open(StandardProtocolFamily.INET).setOption(StandardSocketOptions.SO_REUSEADDR, true)
    .setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface);
datagramChannel.configureBlocking(true);
datagramChannel.bind(new InetSocketAddress(filter.getType()
    .getPort(filter.getTimeFrameType())));
datagramChannel.join(group, networkInterface);
datagramChannel.receive(buffer);

このコードは にあり、最大 12 の s (したがって 12 のスレッド)Callableを作成して、Callable12 の異なるポートから異なるデータを含むマルチキャスト パケットを取得します。3~8秒ごとにネットワーク上で放送されている情報から読み取るだけです。

12 個のポートを継続的にプールすると (情報を待ち、情報を取得するなど)、CPU の 1 つを 100% 消費します。

JVisualVM で実行をプロファイリングすると、実行時間の 90% が 、java.nio.channels.DatagramChannel#receive()より正確には に費やされていることがわかりcom.sun.nio.ch.DatagramChannelImpl#receiveIntoBuffer()ます。

  1. ブロッキングモードがCPUを大量に消費する理由がよくわかりません。

  2. ブロッキング モードの代わりに sを使用する記事をいくつか読みましたが、 withがブロッキング チャネルより消費量が少ないSelector理由がよくわかりません。while (true)Selector

4

1 に答える 1

1

問題は、セレクタなしで NIO を使用していることです。

Selector のない NIO を使用しても問題ありませんが、Channel.receive は常に読み取りを試み、1 つのスレッドの CPU 使用率が高くなります。

2つの解決策があります:-

  • Selector を使用して、読み取るものがあるかどうかを検出します。読み取るデータがあることを Selector が示している場合にのみ、channel.receive を呼び出します。
  • ブロッキングモードで送受信するには、java.net.DatagramSocket/DatagramPacket を使用します。
于 2014-11-05T08:14:22.377 に答える