3 ms·
I've been doing some performance tuning in Go lately to really squeak performance, and ended up with a very similar arena design except using byte slices for bu
by silisili 2y ago
I've been doing some performance tuning in Go lately to really squeak performance, and ended up with a very similar arena design except using byte slices for buf and chunks instead of unsafe pointers. I think I tried that too and it wasn't any faster and a whole lot uglier, but I'll have to double check before saying that with 100% confidence.
A couple other easy wins -
if you start with a small slice and find some payloads append large amounts, write your own append that preemptively is more aggressive in cap bumping before calling the builtin append.
unsafe.String is rather new and great for passing strings out of byte slices without allocating. Just read the warnings carefully and understand what you're doing.
- PaulKeeble 2y agoThe append(slice,slice2...) code is all well and good but its going to hit into the expansion quite often. When you know the second append is going to be large its often faster to allocate a new slice with the right size and no elements and then append both slices to it, then there is no expansion costs the values just get copied in and it also produces less garbage to be collected. I have done a few other things in the past where I had sliceLike's which took two slices and point to one and then the other and a function mapped to the indices as if they were appended, costs a bit on access but saves on the initial allocation if you don't intend to iterate through the entire thing or only do so once. The base library in go does not do much for optimising this sort of thing, its not a dominate operation in most applications so I can see why we don't have more advanced data structures and algorithms. You have to be quite heavily into needing different performance characteristics to outperform the built ins with custom code or a library. All parts of Go's simplicity push that seems to assume people don't need anything else other than Array Lists and hash maps.
- mischief6 2y ago> All parts of Go's simplicity push that seems to assume people don't need anything else other than Array Lists and hash maps. you can see some of this in the work of the progenitors of Go. quoth pike style, from rob pike: Rule 4. Fancy algorithms are buggier than simple ones, and they're much harder to implement. Use simple algorithms as well as simple data structures. The following data structures are a complete list for almost all practical programs: array linked list hash table binary tree Of course, you must also be prepared to collect these into compound data structures. For instance, a symbol table might be implemented as a hash table containing linked lists of arrays of characters. https://doc.cat-v.org/bell_labs/pikestyle https://doc.cat-v.org/bell_labs/pikestyle
- jerf 2y agoI think the way to look at it is that there's a lot of programs that don't need more than slices, maps, and combinations of said. We know this is true, because dynamic scripting languages lean even more heavily into that, plus they do it with generally worse performance, and there are still many programs that those languages are perfectly suited for. Not every language has to have all the highest performance features pushed to the n'th degree. If you sit down with a set of needs that needs that high performance stuff, that intensely needs custom data structures beyond those, and then you choose Go, the mistake isn't that Go doesn't have every last high-performance option, the mistake is, you shouldn't have chosen Go, anymore than you should sit down with those requirements and choose Perl. Though you may be able to get farther with Go, it was still the wrong choice on your part. I certainly look a bit askance at everyone who says "I'm going to write a high performance database to compete in the commercial database market!" and chooses Go... which is a surprisingly large group. That's not where this article comes from but it's where a lot of the other articles about super-optimizing Go comes from... but the real answer is, they probably shouldn't have chosen Go. On the other hand, there's definitely always been a contingent of people out there who sit down to write a website that will get several dozen hits an hour and think they need to grab Rust and start banging out high performance async code without any framework assistance (can't afford the slowdown of abstraction, you know) with custom data structures and custom database code and "should I use mmap to access the file I'm storing all the data or should I use io_uring?" when in fact a pure-Python Django website backed to a conventional database that they forgot to even index properly would have humanly-indistinguishable performance. Engineers screw up their performance requirements analysis all over the place. It's probably one of the bigger and more consequential mistakes made by engineers that we rarely talk about here.
- kweingar 2y agoI learned programming from a Java 7 book in high school. When I went through the Tour of Go, I found myself shocked that anybody would want to write software in a language like this. Where is inheritance? Where is the data structures package? I couldn't even find a standard linked list. What if I have a list where I need to make lots of insertions in the middle? My 15-year-old self would be shocked at my day-to-day as an engineer now.
- alexjplant 2y ago> You have to be quite heavily into needing different performance characteristics to outperform the built ins with custom code or a library. All parts of Go's simplicity push that seems to assume people don't need anything else other than Array Lists and hash maps. Every 2000s-era Enterprise Java project I worked on was written by people that used ArrayList<T> for everything. My classmates' programs were much the same way in college. I wonder if the Golang authors observed similarly and came to this conclusion.
- ignoramous 2y ago> ... small slice and find some payloads append large amounts, write your own append that preemptively is more aggressive in cap bumping before calling the builtin append ... gVisor netstack (userspace TCP/IP) uses a copy-on-write, reference-counted, tiered-pool for their arena-like alloc needs: https://gvisor.dev/blog/2022/10/24/buffer-pooling/ https://gvisor.dev/blog/2022/10/24/buffer-pooling/ / https://archive.vn/YzB1C https://archive.vn/YzB1C The downside of their approach is, the client code is no longer dealing with just []byte (although, both the View and the Buffer type can vend out []bytes).