7 ms·
Most of these techniques sacrifice readability so before implementing them, you should really profile to make sure that the code in question is a hot spot in te
by kevinconaway 7y ago
Most of these techniques sacrifice readability so before implementing them, you should really profile to make sure that the code in question is a hot spot in terms of allocations or CPU usage.
That said, the example using sync.Pool is not quite right. The New function should always return a pointer type to avoid incurring an additional allocation on Get [0]
The code should look like:
var bufpool = sync.Pool{
New: func() interface{} {
buf := make([]byte, 512)
return &buf
}}
b := *bufpool.Get().(*[]byte)
defer bufpool.Put(&b)
[0] see example in https://golang.org/pkg/sync/#Pool https://golang.org/pkg/sync/#Pool
- likeabbas 7y agoSo maybe we should sacrifice compiler speed for having a better compiler optimize more readable code?
- SallySwanSmith 7y agoIsn’t that the entire point of higher order programming languages?
- weberc2 7y agoWhat are "higher order programming languages"? Did you mean "higher level programming languages"? If so, no, the point is that you can program more abstractly, almost always at the expense of performance. EDIT: Downvoters, I'm terribly curious which of these points you disagree with? Do you believe higher level languages (like Python, JS, or even Go) are faster than lower level languages (like C, C++, etc)? Or do you believe that HLLs are actually faster (or meant to be faster) than LLLs? Or maybe you are downvoting because I don't know what a "higher order language" is?
- sagichmal 7y agoThe downvotes are because you have chosen to make an irritating pedantic point about word use when the meaning was entirely clear in context.
- weberc2 7y agoWasn't trying to be pedantic; whatever is "entirely clear in context" is not entirely clear to me at all. Did he use a term that I'm unfamiliar with or did he use the term I'm familiar with in a way that is incongruent with my understanding?
- indentit 7y agoMost compilers skip optimizations when compiling in debug mode, so that it is still quick to iterate/test, then perform the optimizations which take longer to compile for release builds. Obviously it means one can only profile code when it has been compiled in release mode, which I guess has its drawbacks...
- weberc2 7y agoI do wish Go would do this. The fast compiler thing is fantastic, but I think we can have the best of all worlds by supporting a --release flag, and I think Go is large enough now that we can justify the extra maintenance cost of dealing with two compilation modes.
- innocentoldguy 7y agoIs a "fast compiler" really all that impressive though when a lot of the speed comes from not checking things that other compilers do?
- adrianN 7y agoDoes it really matter how the compiler does it? Faster compilation speed makes programmers happier. And it's not like you can convince a C++ or Rust or Scala compiler to just trust you with the types this once and compile your program ten times faster.
- 0815test 7y agoType checking is a very small part of Rust compile cost; most of it is due to the extensive use of monomorphized code (resulting in code bloat which is not always well-controlled, to put it mildly), as well as overhead in the LLVM-dependent part of compilation. Some features in the pipeline for Rust should enable some improvements, particularly const-generics and specialization.
- adrianN 7y ago
- sjwhitworth 7y agoThere's a little at the bottom that encourages caution. In a previous draft, I wrote about the importance of proving hot spots before optimising, but took it out as I wanted this to be more a list of techniques. On sync.Pool: good spot. I'll update it - thanks.
- stebalien 7y agoUnfortunately, that's still wrong (I think). Go will still allocate a temporary slice-header on the heap and then de-allocate it when it's dereferenced. I believe the only way to do this without unsafe code is to pool these slice-headers as in https://github.com/libp2p/go-buffer-pool/blob/master/pool.go https://github.com/libp2p/go-buffer-pool/blob/master/pool.go.
- shereadsthenews 7y agoThe risk of write-profile-optimize is that you might write a big slow program with a totally flat profile. If it doesn’t meet performance requirements at that point, then what?
- fwip 7y agoIn your hypothetical scenario, you then optimize whatever is easiest to optimize.
- firethief 7y agoDoes that ever happen?
- ryanworl 7y agoYes. This is the plague of modern software. It is all over the place. So much software today spends all its time chasing pointers, using the cache poorly, and branching wildly. You won't see these aspects of poor design on a sampling profiler. You will see it by running e.g. perf on Linux and seeing pitifully low IPC and cache miss numbers.
- the_duke 7y agoThis is one of the reasons I really love Rust: it not-so-subtly nudges you towards avoiding heap allocations by adding extra boilerplate and making them obvious in type signatures (unless you hide them behind wrapper types). This contributes to Rust programs generally having good performance characteristics without spending time on optimizations.
- firethief 7y ago> This is one of the reasons I really love Rust: it not-so-subtly nudges you towards avoiding heap allocations by adding extra boilerplate and making them obvious in type signatures (unless you hide them behind wrapper types). Could you clarify this? It seems like the opposite to me. Borrowing requires lifetimes in type signatures, but boxing yields owned objects, which can be passed around easily like value types.
- nhooyr 7y agoYour example doesn't seem right. Doesn't the Get perform an allocation anyway because you access the value of the pointer and store it in a new variable b? It's very likely b will escape to the heap.
- peterwaller 7y agoI agree with nhooyr's analysis. The interface{} will anyway transparently "contain" a pointer-to-the-[]byte, in other words, the []byte value itself will be heap allocated. (Note for anyone new to this that the "[]byte-value" - we say "the byte slice" - is a distinct thing from the "values stored-in-the-byte-slice", which is a heap allocated backing array)