Questions about buffered streams

R

Roedy Green

No they don't.

Check out the code for BufferedReader.skip. An IDE like IntelliJ Idea
will take you to the source from any reference with Ctrl-B. It HAS to
track where it is in the buffer because the OS knows nothing about the
buffer.

Check out the code for FileInputStream.read (the basic read routine).
It is a native method. It might or might not maintain a mirror copy
of the physical cursor position. I don't see how you can be so
certain. It could be different on different platforms. In any case,
logically read does track the physical cursor location. Consider that
Java could be implemented on a file system without sequential files,
just random access. This would be disguised in the native methods.
 
R

Roedy Green

I'm not sure how you got the impression that article got me
confused?

I thought I had answered all your question in the essay. You were
still asking questions. That implied something in the essay was
inadequate or confusing.
 
R

Roedy Green

.
.
fo.write(byte_64000);

would be just as efficient as if buffered stream flushed those 64000
bytes?

for large chucks UNbuffered streams are more efficient, though they do
the same thing physically. If you turn off buffering you save the
copying and RAM for buffers.

1. Try to read the file all in one go, so long as it is small enough
to process that way. Use UNbuffered.

2. Otherwise buffer, and read a chunk, line, field or char at a time.

3. Use code like than in FileTransfer for bulk copying files or
downloaded streams. It reads a large chunk at a time unbuffered.

4. Buffering is needed for readLine.
 
R

Roedy Green

Perhaps it was your assertion that 64K individual writes of one byte would
proceed faster than a single write of 64K bytes that gave that impression.

Here is how I have rewritten the section. I hope this makes
everything clear:

Because of hard disk latency, when you do I/O, it will go faster if
you do it in a few big physical I/O chunks rather than a number of
small ones. If you wrote data one byte at a time, you would have to
wait for the disk arms to snap to the correct cylinder, and for the
platter to rotate round the correct spot every time you wrote a byte.
If you buffered at 64,000 characters, you would have to do this wait
only once every 64,000 characters. Mechanical motion is in the order
of 1000 times slower than electronics.

If you wrote a byte at a time, since the hardware works in 512-byte
sectors at a time, the OS would need to read the sector, plop your
byte into it and write the entire sector back. This would take at
least 2 disk rotations, perhaps 3. Even if you wrote your data 512
bytes at a time, when you went to write the next sector, its spot
would have just past the head, so you would have to wait an entire
rotation for its spot to come round. If you wrote 131,072 bytes (still
less than 1 physical track) at a pop, you could do that all in one
rotation.

Ideally, if you have enough RAM, you do the I/O in one whacking huge
file-sized unbuffered chunk. Java has a number of classes that let you
process a file buffered in convenient small logical chunks, often line
by line. The buffered classes transparently handle the physical I/O in
bigger chunks, typically 4096 bytes. The classes store each large
chunk for physical I/O in a separate piece of RAM called a buffer.
Unless the buffer size for the physical I/O is at least twice as big
as the size of the logical chunks you process, there is not much point
in buffering. The extra buffering copying overhead will just slow you
down.

The File I/O Amanuensis will teach you how to do I/O either buffered
or unbuffered. You can try it both ways, and see which works faster.
You can also experiment with buffer sizes. The bigger the buffer, the
fewer the physical I/Os you need to process the file. However, the
bigger the buffer, the more virtual RAM you will use, which may
trigger more swapping I/O. Further, there is not much point in having
a whacking big buffer for a tiny file. It will take only a few I/Os to
process the file anyway.

You will find that buffer sizes that are a power of two tend to work
faster than other sizes. This is because disk and RAM hardware are
designed around some magic sizes, typically 256, 512, 1024, 2048,
4096, 8192, 16,384, 32,768, 65,536, 131,072 and 262,144 bytes. Buffers
that are powers of two naturally do I/O in physical chunks that align
on powers of two boundaries in the file. This too makes the I/O more
efficient because the hardware works typically in 512 byte sector
chunks. If you do unbuffered I/O, likewise try to start your I/Os on
boundaries that are even multiples of some power of two, the higher
the power of two the better. e.g. it is better to start I/O on
boundaries that are even multiples of 8096 rather than just 128.
Sometimes it pays to pad your fixed-length records up to the next
power of two. If you can help it, arrange your logical record size and
buffer size so that logical records are aligned so that they never (or
rarely) span two buffer fulls. It also helps to have your buffers
aligned on physical RAM addresses that are even powers of two as well,
though you have no control of that in Java.

In the olden days, CØBØL programs used double buffering. They used two
or more buffers per file. The computer would read ahead filling
buffers while the program was busy processing one of the previous
buffers. Oddly, Java does not support this efficient serial processing
technique, though sometimes the operating system maintains its own
private set of read-ahead buffers behind the scenes. Unfortunately,
the OS's cascaded buffering is less efficient than using a single
layer. You have the overhead of copying plus the wasted RAM for the
buffers that are not actually used for physical I/O. Java never has
more than one buffer per file and hence cannot simultaneously process
and do physical I/O, unless of course it uses Threads. Even with
Threads, you can’t pull off double buffering with any ease.

The term double buffering also refers to a technique of constructing
Images off screen then blasting them onscreen once they are complete,
as a way of creating smoother animation.

If you wrote 128K a byte at a time using a 64K buffer there would be
only two physical 64K I/Os. This would be slightly slower that using
unbuffered I/O to write the entire 128K in one I/O because of the
extra physical I/O, the RAM overhead for the buffer and the CPU
overhead of copying the data to the buffer.

When To Buffer

To process a file whole file a time, read the entire file in one giant
unbuffered I/O.

If a file is too large to process all in RAM, read it buffered, and
process it a chunk, line, field or char at a time.

To copy files or download streams use the FileTransfer class which
reads unbuffered a large chunk at a time.

If you need the readLine method, you must use buffering.
 
C

Christian

Roedy said:
If you wrote a byte at a time, since the hardware works in 512-byte
sectors at a time, the OS would need to read the sector, plop your
byte into it and write the entire sector back. This would take at
least 2 disk rotations, perhaps 3. Even if you wrote your data 512
bytes at a time, when you went to write the next sector, its spot
would have just past the head, so you would have to wait an entire
rotation for its spot to come round. If you wrote 131,072 bytes (still
less than 1 physical track) at a pop, you could do that all in one
rotation.

I doubt it is that simple with a modern OS.
As discs have large caches that buffer read/write operations.
The OS has a cache that does additional buffering shure these caches may
be slower than your buffer that may reside in the cache of the cpu...
but that doesn't mean you can measure or explain the latency of writing
single bytes with hdd rotation.
 
L

Lew

I doubt it is that simple with a modern OS.
As discs have large caches that buffer read/write operations.
The OS has a cache that does additional buffering shure these caches may
be slower than your buffer that may reside in the cache of the cpu...
but that doesn't mean you can measure or explain the latency of writing
single bytes with hdd rotation.

Let us not forget the effect of file systems. A journaling file system will
add more physical writes to the logical writes that Java requests, further
complicating matters. And we aren't talking RAID, even. As others have
pointed out, the issues pertain if disks aren't even involved, as with TCP/IP
streams.

It is next to useless to talk about platters and heads and disk spin in a Java
context. Just about any IO Stream will behave better with larger chunks, up
to a point, even if it's only because of the CPU chip's own internal memory
cache. Memory accesses are striped, too.

The rule of thumb is that a write() carries overhead. The penalty of that
overhead is reduced with a larger payload - the Automated Teller Machine (ATM)
fee effect. The larger the transaction, the smaller the fee in proportion to it.

For just about all practical IO Streams, the write() overhead is large enough
to make that 64KB go much faster as one write than as 64K individual one-byte
writes. Disks, platters and heads are not even in that overhead any more [1]
- it's all OS, file-system and driver in-memory overhead and cache accesses,
mobo and outboard both.

[1] for the large category of applications not requiring guaranteed writes
(e.g., not RDBMSes).
 
J

John W. Kennedy

Roedy said:
In the olden days, CØBØL programs used double buffering. They used two
or more buffers per file. The computer would read ahead filling
buffers while the program was busy processing one of the previous
buffers. Oddly, Java does not support this efficient serial processing
technique, though sometimes the operating system maintains its own
private set of read-ahead buffers behind the scenes. Unfortunately,
the OS's cascaded buffering is less efficient than using a single
layer.

Double buffering is an operating-system feature on IBM mainframes
(actually, these days, it's more likely to be quintuple buffering),
having nothing much to do with the language a program is written in.
Similarly not having double buffering is more a function of *ix and
Windows than of Java or C.
To process a file whole file a time, read the entire file in one giant
unbuffered I/O.

Or use MappedByteBuffer.
To copy files or download streams use the FileTransfer class which
reads unbuffered a large chunk at a time.

File copying is most efficiently performed by the transferTo and
transferFrom methods of FileChannel.

--
John W. Kennedy
"The whole modern world has divided itself into Conservatives and
Progressives. The business of Progressives is to go on making mistakes.
The business of the Conservatives is to prevent the mistakes from being
corrected."
-- G. K. Chesterton
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,534
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top