Could someone advice in Go caching?

polaris · · 437 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I created a library for Right/Left string padding which has variable allocation <code>caching</code> for common use cases: <a href="https://github.com/Rhymond/gopad/blob/master/gopad.go#L8" rel="nofollow">https://github.com/Rhymond/gopad/blob/master/gopad.go#L8</a></p> <p>Is it good practice to do that? I&#39;m looking for an advice, thanks in advance!</p> <hr/>**评论:**<br/><br/>metamatic: <pre><p>Given <a href="http://herman.asia/efficient-string-concatenation-in-go" rel="nofollow">how cheap</a> appending one byte to a <a href="https://golang.org/pkg/bytes/#Buffer" rel="nofollow">Buffer</a> is, I&#39;m very skeptical that you&#39;ll get any speedup by having pre-build 2, 3, 4 and 5 byte sequences.</p> <p>In fact, given modern CPU architectures, I suspect that appending one byte to a buffer 5 times is going to be faster than going out to main memory to fetch a sequence of 5 bytes you created at compile time.</p></pre>tscs37: <pre><p>appending is only cheap when the capacity is sufficient.</p> <p>From experience, pre-allocating a buffer in memory instead of allocating til max capacity is a factor of 1.5 to 2 times in performance until the cache is fully warmed.</p> <p>The reason is that if the capacity is not sufficient, you will most likely have to hit the runtime or even worse, malloc.</p> <p>In a tight loop, going into runtime or doing a syscall can shit all over the cache and worsen performance.</p></pre>raima220: <pre><p>I though the same before, but I made benchmarks:</p> <p>With &#34;Cache&#34;: BenchmarkPad-8 300000 3673 ns/op</p> <p>Without: BenchmarkPad-8 300000 4579 ns/op</p> <p>You can find my benchmark test here:</p> <p><a href="https://github.com/Rhymond/gopad/blob/master/gopad_test.go" rel="nofollow">https://github.com/Rhymond/gopad/blob/master/gopad_test.go</a></p></pre>metamatic: <pre><p>Interesting. I&#39;m surprised that (a) it&#39;s faster and (b) by that much.</p> <p>Would be interesting to look at the generated code, if I knew X86 assembler...</p> <p>I did some more tests, and it&#39;s even faster if you just keep the buffer around and reset it, rather than creating a new buffer every time. I&#39;m also inclined to optimize for the common case of only wanting to pad with a single rune; I don&#39;t think I&#39;ve ever wanted to pad with more than one.</p> <pre><code>var buff bytes.Buffer func spad(s string, l int, ch rune, isl bool) string { buff.Reset() sl := utf8.RuneCountInString(s) n := l - sl if n &lt;= 1 || l &lt; 1 { return s } if !isl { buff.WriteString(s) } for ; n &gt; 0; n-- { buff.WriteRune(ch) } if isl { buff.WriteString(s) } return buff.String() } </code></pre></pre>xienze: <pre><blockquote> <p>and it&#39;s even faster if you just keep the buffer around and reset it</p> </blockquote> <p>But then you&#39;re not thread-safe unless you control access to the buffer, which will slow you right back down. Or you can make the caller provide the buffer, but that&#39;s an inconvenience and a bit of a leaky abstraction. Tradeoffs.</p></pre>metamatic: <pre><p>Indeed. And the whole thing&#39;s an exercise in premature optimization to start with.</p></pre>xienze: <pre><p>Well it depends. If this string padding function is going to get called all the time then OP&#39;s idea is a good move. If it&#39;s just used occasionally and not in a hot path? Who cares.</p></pre>hell_0n_wheel: <pre><p>What problem did you solve by writing that code?</p> <p>Did you profile the code before and after adding the solution, to confirm it did what you expected?</p></pre>raima220: <pre><p>Yes, and it looks like that <code>cached</code> is faster</p> <p>With &#34;Cache&#34;: BenchmarkPad-8 300000 3673 ns/op</p> <p>Without: BenchmarkPad-8 300000 4579 ns/op</p> <p>You can find my benchmark test here:</p> <p><a href="https://github.com/Rhymond/gopad/blob/master/gopad_test.go" rel="nofollow">https://github.com/Rhymond/gopad/blob/master/gopad_test.go</a></p></pre>hell_0n_wheel: <pre><p>Well then you answered your own question.</p> <p>As you stated it here, there&#39;s no context for your question, so we can&#39;t understand it, let alone give you a good answer.</p> <p>Consider this next time you post: <a href="https://cs.stackexchange.com/help/how-to-ask" rel="nofollow">https://cs.stackexchange.com/help/how-to-ask</a></p></pre>Snabel3: <pre><p>The cache is not optimal as a array since the code will have to look up the pointer to the value every time. I don&#39;t think you are earning any performance with all these lookups. </p> <p>The cache should be a constant (if used at all). </p> <p>Try using string.Repeat() with a single space instead of a for-loop and use a slice to get the length you want. Should be cleaner and safer code. </p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

437 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传