简体   繁体   中英

Efficient read/write approach with Java NIO

Let's say we have SocketChannel (in non-blocking mode) that registered with Selector for read interest. Let's say after select() Selector tells us that this channel is ready for read and we have some ByteBuffer. We want to read some bytes from our channel to this buffer (ByteBuffer is cleared before reading). For this we use channel's read() method that returns actual number of bytes read. Lets suppose that this number is positive after read from channel and also ByteBuffer's method hasRemaining() returns true. Is it practical in this situation to immediately try to read from same channel some more? The same question for write(). If write() returns positive value and not all contents of the buffer was sent, is it practical to immediately try again until write() returns zero?

It all depends on the data rate at which data is arriving, and the latency requirements of your application. If you don't care about latency at all, you might get slightly higher bandwidth by delaying your read interest until you suspect enough data has arrived to fill your buffer.

You have to be careful, though. Delaying reads could force the kernel to buffer more data, possibly fill its buffer, and have to start dropping packets or otherwise engage some flow control. That will more than kill any benefits from the last paragraph.

So generally, you want to read as much as you can, as early as you can. The benefits for batching reads are minor at best, and the potential pitfalls can be major. And keep in mind that the fact that you're seeing non-full reads means you're processing the data faster than it is coming in. In other words, you're in a state where you have CPU to burn, so the extra overhead of smaller reads is essentially free.

If you get a short read result, there is no more data to read without blocking, so you must not read again until there is. Otherwise the next read will almost certainly return zero or -1.

If the read fills the buffer, it might make sense from the point of view of that one connection to keep reading until it returns <= 0, but you are stealing cycles from the other channels. You need to consider fairness as well. In general you should probably do one read and keep iterating over the selected keys. If there's more data there the select will tell you next time.

Use big buffers.

This also means that it's wrong to clear the buffer before each read. You should get the data out with a flip/get/compact cycle, then the buffer is ready to read again and you don't risk losing data. This in turn implies that you need a buffer per connection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM