我正在研究一个基于NIO和socket通道的最小服务器概念,可以将数据从一个端口流向另一个目标。
当网络速度很快时,一切都运行良好。但是当一侧比另一侧更快时,情况非常糟糕,会导致CPU占用率大幅增加,效率极低。
例如:
Iterator keys = selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = (SelectionKey) keys.next();
keys.remove();
try {
if (!key.isValid()) continue;
if (key.isReadable()) read(key);
}
catch (Exception e) {
e.printStackTrace();
key.cancel();
}
}
当套接字有可读数据时,就会发生读取调用。但是如果由于客户端延迟高或只是不能快速读取数据而无法将此套接字的可写部分写入,会怎样呢?我们最终会以疯狂的速度循环执行无操作,直到更多可写缓冲区释放出来:
public void read(SelectionKey key) throws IOException {
ByteBuffer b = (ByteBuffer) buffers.get(readable); //prior buffer that may or may not have been fully used from the prior write attempt
int bytes_read = readable.read(b);
b.flip();
if (bytes_read > 0 || b.position() > 0) writeable.write(b);
b.compact();
}
假设我们可以以每秒1千兆比特的速度从套接字中读取数据,但是接收方只能以每秒100千比特的速度从我们可写的套接字中读取...因此,由于客户端并不能像我们希望的那样快速消耗套接字缓冲区中的数据,我们可能需要在每个小数据块之间循环一百万次,才能将其写入客户端。
如果使用线程进行操作,则没有问题,因为我们会在写入调用上阻塞。但是使用NIO时,你应该怎么做才能让它跳过读取通知呢?