<p>I'm trying to measure network download speed by creating multiple streams to download large files via go's Net library. I'm recording the total speed by summing up speeds from individual streams. Since I don't have any use for the actual data in the streams and I don't want to flood the memory with large chunks of downloaded data, I wanted to know if there's a way to remove data from these internal buffers of io.Reader OR does the Read() method clear them itself after a Read call ?</p>
<hr/>**评论:**<br/><br/>captncraig: <pre><p>note that io.Reader is an interface. There are many implementations which do different things. If it is a network request like you are using, then you can use the same buffer over and over again:</p>
<pre><code>buf := make([]byte,128*1024)
for{
conn.Read(buf)
}
</code></pre>
<p>This loads straight from the os memory into your buffer. There is no additional allocation.</p></pre>dlsspy: <pre><p>But it's a copy. You could avoid the copy with a ReaderFrom</p></pre>captncraig: <pre><p>got an example?</p></pre>dlsspy: <pre><p>I'm not sure off the top of my head how to do it in that direction. io.Copy automatically does it in the other direction from a file to a TCP connection. io.Copy to ioutil.Discard would be the first thing I'd try for this type of problem, though.</p></pre>captncraig: <pre><p>even that allocates an 8k buffer (at least it is a pooled buffer): <a href="https://golang.org/src/io/ioutil/ioutil.go#L147" rel="nofollow">https://golang.org/src/io/ioutil/ioutil.go#L147</a></p></pre>dlsspy: <pre><p>Yes, Discard does. There was a bug where it used to not and bad things happened.</p></pre>xargon7: <pre><p>Yes, but memory bandwidth should <em>far</em> exceed network bandwidth (e.g. 4+GB/sec vs ~100MBps for a saturated Gbps network), so it shouldn't matter.</p>
<p>You can avoid any heap allocation using an array:</p>
<pre><code>var buf [128*1024]byte
for {
if _, err := conn.Read(buf[:]); err != nil {
break
}
}
</code></pre></pre>dlsspy: <pre><p>I prefer <code>io.Copy</code> for simplicity in most cases. On one hand, you're reinventing it when you make a loop, but on the other, you're removing its ability to optimize.</p>
<p>Array or slice doesn't make a difference WRT heap. Your buf escapes to heap.</p>
<pre><code>$ nl -ba x.go
1 package main
2
3 import (
4 "io"
5 "strings"
6 )
7
8 func WithArray(r io.Reader) error {
9 var buf [128 * 1024]byte
10 for {
11 if _, err := r.Read(buf[:]); err != nil {
12 return err
13 }
14 }
15 }
16
17 func main() {
18 WithArray(strings.NewReader("x"))
19 }
$ go build -gcflags -m
# misc/x
./x.go:18: inlining call to strings.NewReader
./x.go:9: moved to heap: buf
./x.go:11: buf escapes to heap
./x.go:8: leaking param: r
./x.go:18: strings.NewReader("x") escapes to heap
./x.go:18: &strings.Reader literal escapes to heap
</code></pre></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传