'Wrapping the same `io.Reader` multiple times with a `bufio.Reader` and calling `ReadByte`: will this cause problems?
Suppose I have the following program (error checking removed for simplification):
func F(r io.Reader) {
b := make([]byte, 1)
for ii := 0; ii < 3; ii++ {
r.Read(b)
if b[0] == 'f' {
break
}
}
}
func G(r io.Reader) {
b := make([]byte, 1)
for ii := 0; ii < 3; ii++ {
r.Read(b)
if b[0] == 'g' {
break
}
}
}
func main() {
r, _ := os.Open("some_file.txt")
F(r)
G(r)
}
Every r.Read, functions F and G inspect the next byte in the io.Reader, and determine whether they should continue reading or not depending on the read byte.
I was thinking of rewriting the functions as follows:
func F(r io.Reader) {
br := bufio.NewReader(r)
for ii := 0; ii < 3; ii++ {
if b, _ := br.ReadByte(); b == 'f' {
break
}
}
}
func G(r io.Reader) {
br := bufio.NewReader(r)
for ii := 0; ii < 3; ii++ {
if b, _ := br.ReadByte(); b == 'g' {
break
}
}
}
For this case, there shouldn't be much of a reason to choose the second implementation over the first, but if we change 3 to 10000, maybe so.
Will wrapping io.Reader inside a bufio.Reader and calling ReadByte cause the original io.Reader to go "beyond" such that calling G after F using the same io.Reader may cause errors?
Solution 1:[1]
Wrapping buffers is redundant and will result is some extra usage of cpu/memory.
But it is not wrong.
If we are talking about small chunks of data and the cost to update the code is bigger than other tasks, perhaps you can keep this way.
My advice is to write some benchmarks. This can guide you to find where you should focus.
But you can:
- Force the parameter to be an
*bufio.Readerin G, F - Keep io.Reader as parameter. Check if it is a bufio.Reader and if not, wrap it.
- Consider chain the functions
type Consumer func(io.Reader)
type ChainConsumer func(Consumer) Consumer
func G(r io.Reader) {
// same code
}
func ChainedF(next Consumer) Consumer {
return func(r io.Reader){
// F here, then
next(r)
}
}
func ChainedBuffered(next Consumer) Consumer {
return func(r io.Reader){
br := bufio.NewReader(r)
next(br)
}
}
…
r, _ := os.Open(…)
chain :=
ChainedBuffered(ChainedF(G))
chain(r) // voila
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Tiago Peczenyj |
