-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bytes: return EOF early in Reader.Read #21852
Comments
We can change |
And by the way strings.Reader behaves the same |
And the last thing. buffer.ReadFrom always does reallocation when there is less than 512 bytes of free space. So currently it's absolutely useless to preallocate small amounts of memory manually. buffer.ReadFrom function has loop inside, What do you guys think about skipping reallocation on the first iteration of the loop? Just to give some context, I'll describe my use case.
|
If we fix This will of-course always allocate if |
Even though this is true, I'd think twice before fixing what's not broken. I guess there are/may be programs in the wild depending incorrectly on the current behavior. |
I tried to change bytes and strings Reader once to do early EOF and a gazillion tests broke. I didn't deem it worth it. Hopefully the io.Reader signature would be different in Go 2 |
(that was years ago. Maybe it's gotten better but I doubt it. I suspect more failures) |
Sigh... incorrect usages of |
No, it wasn't incorrect usages. It was just tests expecting a certain golden behavior output from things. |
In my test, there were about 40 failures. By far, the most common failure is code doing the equivalent of: b := make([]byte, n)
if _, err := r.Read(b); err != nil {
return err // Assume err != nil implies something went drastically wrong.
}
// Use b assuming it read n bytes... This is a straight up wrong use of There were a small handful that I guess you could call "golden behavior" changes, and they have to deal with the use of |
I don't understand why this issue is still open. It's a golang-nuts question. The issue is an XY problem: "I have a bytes.Reader reader and I want to copy its contents to bytes.Buffer using the ReadFrom method." "The XY problem is asking about your attempted solution rather than your actual problem (http://xyproblem.info)." The issue is a performance question, but there are no Go benchmarks, only example code (https://play.golang.org/p/j7S3hNkEB5). The solution to the actual problem, I have a bytes.Reader reader and I want to efficiently copy its contents to bytes.Buffer, is to use io.Copy (an implicit io.WriteTo) or io.WriteTo. Don't use io.ReadFrom. For example, see BenchmarkCopy and BenchmarkWriteTo,
rf_test.go: https://play.golang.org/p/ZB-CtPqJHJ |
I disagree. |
@peterGo, I don't understand what your objection actually is. The use of That being said, I'm leaning against making any change to |
Having analyzed the failures, most of them are obviously wrong similar to my example above: b := make([]byte, n)
if _, err := r.Read(b); err != nil {
return err // Assumes err != nil always means failure, and forgets to handle io.EOF specially
} If making this change breaks code that does something similar to the above, then that's a good thing. It's exposing a bug that was always there. Given that it is after the freeze and this is not a bug fix, I'm pushing this to the next milestone. |
SGTM |
It looks like no one is working on this, so I'll give it a go. I have a draft CL; will mail after polishing it a little more. I've been thinking perhaps we should randomly pick whether to return EOF with the last Read. Somehow that idea sounds simultaneously terrible and terribly tempting. |
Change https://golang.org/cl/138588 mentions this issue: |
Sorry but I don't think we can reasonably change this. The bytes and strings Reader.Read behavior is what it is, and that is not returning EOF until there's nothing else to return (just like bufio.Reader.Read). Like Brad said back in 2017. The original report was not about EOF. It was about trying to an efficient copy from a bytes.Reader into a bytes.Buffer. Don't use ReadFrom for that. Use WriteTo, which can do a better job. Even better, use io.Copy, which is clearer and knows tricks like "WriteTo is better than ReadFrom". |
I have a bytes.Reader reader and I want copy it contents to bytes.Buffer using ReadFrom method. I create buffer with preallocated space and expect that additional allocations will not happen.
Instead buffer allocates twice more memory than required to store data. This happens because bytes.Reader doesn't return EOF immediately when it reaches end of stream. Instead it returns EOF only on the next call to Read causing bytes.Buffer to double it's underlying storage.
Link to example code https://play.golang.org/p/j7S3hNkEB5
Code consists of 3 blocks.
First one demonstrates bytes.Reader behaviour.
Second one demonstrates bytes.Buffer.ReadFrom behaviour with preallocated space
Third one avoids reallocation by preallocating slightly bigger buffer
My go version is 1.9
The text was updated successfully, but these errors were encountered: