java nio cpu select() 与 selectNow() 时的使用问题
java nio cpu usage issues when select() vs selectNow()
我尝试使用 select() 与 selectNow(),差异很大 cpu 如果使用 selectNow(),我知道select() vs selectNow() 是阻塞操作和非阻塞操作,那么如何解决这个问题呢?它是 JDK8 中的错误吗?还是我的代码错误?
public static void main(String args[]) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(9001));
channel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("The server listened at " + LocalDateTime.now() + " on port 9001");
Iterator<SelectionKey> iterator;
SelectionKey key;
while (true) {
selector.select(); << ---- Here is the key make CPU usage!
iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
key = iterator.next();
iterator.remove();
if (key.isAcceptable()) {
SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
String address = (new StringBuilder(sc.socket().getInetAddress().toString())).append(":").append(sc.socket().getPort()).toString().replace("/", "");
sc.configureBlocking(false);
sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
sc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
sc.setOption(StandardSocketOptions.TCP_NODELAY, true);
sc.register(selector, SelectionKey.OP_READ, address);
System.out.println("The server accepted at " + LocalDateTime.now() + " from " + address);
}
if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
int read = sc.read(buffer);
if (read == -1) {
key.channel().close();
key.cancel();
} else {
Object object = convertByteToObject(buffer.array());
System.out.println("The server received at " + LocalDateTime.now() + " from " + key.attachment() + " for " + uptimeHttp.HttpRequestAddress);
buffer.clear();
}
}
}
}
}
当您在紧密循环中调用非阻塞操作时,CPU 将尽可能快地迭代,直到您停止它。这通常意味着您将 100% 的 CPU 花费在执行循环上。
如果您看到的小于 100%,则可能是您正在查看用户 CPU,系统调用可能正在使用 CPU.
的其余部分
问题是使用 selectNow()
会导致 Peter 所建议的紧密循环。也就是说,selectNow()
在特定情况下是一个有趣的选项……例如定时操作。您可以使用 selectNow()
和高精度计时器来强制操作以特定频率发生。这是一个非常具体的情况。
因此,如果您想使用 selectNow()
,则必须将其与 Thread.sleep()
或其他等效项配对。
我尝试使用 select() 与 selectNow(),差异很大 cpu 如果使用 selectNow(),我知道select() vs selectNow() 是阻塞操作和非阻塞操作,那么如何解决这个问题呢?它是 JDK8 中的错误吗?还是我的代码错误?
public static void main(String args[]) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(9001));
channel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("The server listened at " + LocalDateTime.now() + " on port 9001");
Iterator<SelectionKey> iterator;
SelectionKey key;
while (true) {
selector.select(); << ---- Here is the key make CPU usage!
iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
key = iterator.next();
iterator.remove();
if (key.isAcceptable()) {
SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
String address = (new StringBuilder(sc.socket().getInetAddress().toString())).append(":").append(sc.socket().getPort()).toString().replace("/", "");
sc.configureBlocking(false);
sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
sc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
sc.setOption(StandardSocketOptions.TCP_NODELAY, true);
sc.register(selector, SelectionKey.OP_READ, address);
System.out.println("The server accepted at " + LocalDateTime.now() + " from " + address);
}
if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
int read = sc.read(buffer);
if (read == -1) {
key.channel().close();
key.cancel();
} else {
Object object = convertByteToObject(buffer.array());
System.out.println("The server received at " + LocalDateTime.now() + " from " + key.attachment() + " for " + uptimeHttp.HttpRequestAddress);
buffer.clear();
}
}
}
}
}
当您在紧密循环中调用非阻塞操作时,CPU 将尽可能快地迭代,直到您停止它。这通常意味着您将 100% 的 CPU 花费在执行循环上。
如果您看到的小于 100%,则可能是您正在查看用户 CPU,系统调用可能正在使用 CPU.
的其余部分问题是使用 selectNow()
会导致 Peter 所建议的紧密循环。也就是说,selectNow()
在特定情况下是一个有趣的选项……例如定时操作。您可以使用 selectNow()
和高精度计时器来强制操作以特定频率发生。这是一个非常具体的情况。
因此,如果您想使用 selectNow()
,则必须将其与 Thread.sleep()
或其他等效项配对。