-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
When calling io.CopyBuffer(writer, reader, buf) , it tries to use the io.ReaderFrom interface on writer if it is available. For example net.TcpConn implemets the io.ReaderFrom and will try to use syscalls like splice or sendfile to avoid additional copy in the user space.
This is all well-intended and provides better performance in the case of copying from one net conn to another. However. If the reader is not a real file, but just some struct implements io.Reader, it actually falls back to using io.Copy.
This is problem-some, as the very intention of using io.CopyBuffer is that we get to control the buffer and potentially pool the buffers to avoid GCs. But the generic fallback to io.Copy makes the buffer passed in useless and makes an additional allocation.
This behavior is clearly shown in the following heap profile (left is the buffer passed in, right is the allocation made by genericReadFrom fallback (io.Copy)):

This is a very surprising behavior to the end developers without the understanding of TcpConn readfrom internals. As an obvious optimization of using io.CopyBuffer in the hot-path turns out to be even worse than just call io.Copy.
So would propose to add an interface similar to io.ReaderFrom, but allows to take additional buffer, thus the name io.ReaderFromBuffer. This way nice optimization regarding fd copies can still happen, but in case none applies, the genericReadFrom can fallback to io.CopyBuffer instead of io.Copy, to take advantage of the buffer passed in, if there is any.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status