假设我们有向 Selector 注册的 SocketChannel(非阻塞模式)以供阅读。假设在 select() 选择器告诉我们该通道已准备好读取并且我们有一些 ByteBuffer 之后。我们想从我们的通道读取一些字节到这个缓冲区(ByteBuffer 在读取之前被清除)。为此,我们使用通道的 read() 方法返回实际读取的字节数。让我们假设这个数字在从通道读取后是正数,并且 ByteBuffer 的方法 hasRemaining() 返回 true。在这种情况下立即尝试从同一频道读取更多内容是否可行?write() 同样的问题。如果 write() 返回正值并且缓冲区的所有内容都未发送,是否可以立即重试直到 write() 返回零?
问问题
2037 次
2 回答
0
这完全取决于数据到达的数据速率以及应用程序的延迟要求。如果您根本不关心延迟,您可能会通过延迟读取兴趣来获得稍高的带宽,直到您怀疑有足够的数据到达以填满您的缓冲区。
不过,你必须小心。延迟读取可能会迫使内核缓冲更多数据,可能会填满其缓冲区,并且必须开始丢弃数据包或以其他方式进行一些流量控制。这不仅会扼杀最后一段的任何好处。
所以一般来说,你想尽可能早地阅读。批处理读取的好处充其量是次要的,而潜在的陷阱可能很大。请记住,您看到非完整读取的事实意味着您处理数据的速度比输入数据的速度要快。换句话说,您处于需要消耗 CPU 的状态,因此额外的较小读取的开销基本上是免费的。
于 2012-08-17T03:09:59.723 回答
0
如果你得到一个短读的结果,没有阻塞就没有更多的数据可以读取,所以在没有阻塞之前你不能再次读取。否则下一次读取几乎肯定会返回零或-1。
如果读取填满缓冲区,从该连接的角度来看,继续读取直到它返回 <= 0 可能是有意义的,但是您正在从其他通道窃取周期。您还需要考虑公平性。一般来说,您可能应该读一读并继续遍历选定的键。如果那里有更多数据,下次选择会告诉你。
使用大缓冲区。
这也意味着在每次读取之前清除缓冲区是错误的。您应该使用翻转/获取/压缩周期取出数据,然后缓冲区准备好再次读取,并且您不会冒丢失数据的风险。这反过来意味着每个连接都需要一个缓冲区。
于 2012-08-17T04:15:42.757 回答