<p>There's a pattern my company uses quite a lot. Take a stream of data (lines of a log file, a kafka topic, whatever) and shard it out to an array of channels using some hashable consistent key, often user ID, to better utilize multi-core machines for doing some realistic processing work (inserting into a DB, or doing calculations, maybe).</p>
<p>Out of curiosity I wanted to build a little library to do this with 'reflect' with the assumption that it'd get someone up and running with the algorithm, and then you could code-gen the strongly typed code later if it worked out for your use case.</p>
<p>When in my benchmarks it wasn't noticeably slower, I decided to start ripping out all the other variables to get the smallest test harness that tested only that tight loop of channel operations and nothing else. The results, maybe 50-70% slower, but still in the nanosecond range, which is nowhere near the multiple-order-of-magnitude difference I predicted.</p>
<p>I'd love some opinions on if there's flaws in my testing methodologies. All of the benchmarks plus some more documentation at this gist:
<a href="https://gist.github.com/crast/61779d00db7bfaa894c70d7693cee505">https://gist.github.com/crast/61779d00db7bfaa894c70d7693cee505</a></p>
<hr/>**评论:**<br/><br/>dgryski: <pre><p>The real issue with reflect is not in these sorts of channel operations which are already expensive, but rather struct and map operations that change from a few processor instructions into an expensive function call.</p></pre>itsmontoya: <pre><p>For your every day use-case. Reflect won't cause much issue. When you get into performance critical low-level code, it's a big problem</p></pre>k_z-: <pre><p>Go polymorphism (interfaces) is a big problem for performance critical code even without reflect to begin with. The fact that they are implicit is convenient but retrospectively a huge performance trade off.</p></pre>Redundancy_: <pre><p>I'm curious if someone has compared Go interfaces to abstract base classes / virtual function tables in terms of performance delta. If we're going to say that they're a huge performance trade-off, we should be comparing to similar polymorphic features in other languages, rather than the non-polymorphic case.</p>
<p>They are significantly better in semantic form for allowing the interface to live with the code that requires it, rather than the code that implements it (See Uncle Bob's writing on the Interface Segregation Principle).</p></pre>epiris: <pre><p>Since this was just a thought exercise, ill share how I performed <a href="https://gist.github.com/cstockton/2c7e9346af7b7daad11bf9a754a3716e#file-chansendn-go-L7" rel="nofollow">unsafe channel sends</a> so I could test the potential value of a bulk chan send function before I wrote an <a href="https://gist.github.com/cstockton/5f2fea4ace0f099b4908a115409f2da3" rel="nofollow">SSA pass</a>. Maybe you could benchmark it too for fun if you wanted, iirc they are about the same speed.</p></pre>sacrehubert: <pre><blockquote>
<p>unsafe channel sends</p>
</blockquote>
<p>Could you elaborate? What's the strategy here?</p></pre>epiris: <pre><p>Calling the runtime function that the compiler generates for a channel send, which takes an unsafe.Pointer instead of the empty interface.</p></pre>sacrehubert: <pre><p>Right, that much I got, but why is this more efficient? What overhead is avoided?</p></pre>epiris: <pre><p>It is more efficient because unsafe.Pointer is essentially free, while the Send method of reflect.Value is not. Anytime you see a reflect.Value there is an immediate cost of 1 allocation due to forcing all Value's to escape to the heap. For Send we require two allocations since it has a param as well the cost of ensuring type safety at runtime. The overhead avoided is the time to Send via reflect minus the time to send via unsafe. You would never do this, but it was relevant to the ops experiment so I shared.</p></pre>sacrehubert: <pre><p>Thanks for the explanation :)</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传