Making a Go program 70% faster by avoiding common mistakes
blog.fmpwizard.com
blog.fmpwizard.com
- store results in variables and don't call the expensive method over and over
- use batch queries for fetching multiple documents at once from your storageAm i missing something as to why this is on the front page ?
Only that fact that it's a social bookmarking site -- so whatever is voted gets to the front page. In other words: lots of HN readers find it interesting.
X.Y.Z.get("Q")
over and over and over again, even though it can't change, and the X, Y, Z, and Q are never that short. Nothing Go-specific about that anti-pattern, I'm afraid.It would be difficult for a compiler to reliably tell whenever a method behaves like a constant without adding to the compilation time - and that simply isn't an option for JIT runtimes nor Go. And given it's a pretty basic optimisation for humans to pick up, I reckon it's also pretty low down on the list of "must have" features for compiler optimisations.
X.Y.Z.get("Q")
X.Y.Z.get("R")
does the runtime resolve the X.Y.Z.get chain once or twice.In any case, that's not what the article was discussing and not what the majority of the comments on HN were discussing either.
I was just trying to make a quick, generic point. If it helps, imagine 4 chained method calls instead.
I haven't checked but if it was just a struct navigation (X.Y.Z.A.C, no method calls) Go probably does just optimize it to the correct offset. But bear in mind that will be an expensive pattern for CPython or Perl, for instance.
No, it's not. A mature compiler backend can successfully do this in most cases (as in, most values in most programs are proved constant). SSA form coupled with SROA, SCCP, aggressive inlining, and memory analyses are really powerful. You just need a mature, optimizing backend.
> Again, nothing specific to Go here; you'd likely be surprised what the compiler can't assume in almost any imperative language.
Mature compilers are pretty good. They can usually figure out things you expect them to. People talk a lot about aliasing and what that means for const and the like, and that's usually where the gotchas lie, but Go, like most type-safe languages, is (presumably) much friendlier to the compiler than C is in this area.
With all due respect, would you please give me a bit more principle-of-charity here? You too often pop up after a post of mine to "correct" your own too-narrow reading of it in the first place. HN is not always discussing programming things strictly in terms of Rust or similar languages; that's still just one region of a rich space.
Whether or not you think Python or Perl is a disaster of a language or not, the fact remains I have, in real life, performed non-trivial speedups of real code experiencing real problems simply by trimming those lookups, and the fact that it wouldn't have been a problem in C++ or Rust or whatever isn't particularly relevant at that point. And the fact also remains that even when the compiler is not bothered, it's still bad software engineering to create such redundant code anyhow, since it's hard to see what the code is really doing under all the cruft. (I was just complaining about how Erlang code tends to create that problem rather a lot on reddit, actually.... another language where the compiler won't save you....) And thus, it is still a perfectly valid point on a diverse site like HN to point these things out.
> you'd likely be surprised what the compiler can't
> assume in almost any imperative language
If you're going to use language like "almost any imperative language" to implicitly mean "almost any imperative language with predominantly dynamic semantics", then you shouldn't be surprised when someone well-versed in static languages comes along to correct such an overbroad interpretation. Reconsider who's being uncharitable here.(And I say this as a Python developer who has actually needed to hoist a lookup out of a loop before.)
An optimizing compiler (which Go 6g/8g isn't really, though that may change) will usually be able to fix this up. The way it typically works is SSA conversion and method inlining followed by global value numbering. But this is not by any means the only way an optimizing compiler can repair this: many optimizing backends (for example, LLVM) have the notion of "readnone" functions that can be GVN'd away as well in many circumstances.
Database requests, and really any IO, is never appropriate to use like this, I'm refering to stuff like itoa.
When you follow this principle, you end up with software that is exactly as performant as it needs to be (or whatever arbitrary standards were set).
I started following HN when I was a novice programmer, so I do appreciate seeing content appropriate for beginners.
Optimization in todays world starts when you're looking at reducing communication volume, lock contention, utilizing your persistence better, replacing locks with atomic operations, ... Those things shouldn't be done on a whim without measurements, because they will make code a lot harder for non-obvious reasons.
In most cases you would of course still name the result yourself, as to indicate that the function call indeed is the same. However for something very semantic, such as `sum(list)`, maybe the only name you could give it, would be something like `list_sum` anyway.
To be more precise, it is only necessary in language where all functions can have side effects. Some language (like D) have the ability to mark a function as "pure" (without side effects), which allow the compiler to perform additional optimizations (and purity validation).
Which makes it, practically speaking, almost all of them...
The title was misleading to me because I thought I'd learn something about Go
The title was misleading to me because I thought I'd learn something about Go, but instead it was about Golang.With all the AlphaGo news going on, it would be significantly less confusing if posts about Golang used 'golang' in the title, at least until we're not seeing two completely different 'go's regularly on the front page.
"Baduk" instead of "go" also makes googling something about the game easier.
This extends to being appropriately thankful when people write guides to avoiding problems which hit someone in month 4 of their job. Did you write that guide? Did I write that guide? No. This guy wrote that guide. Bully for this guy. The world is better off that he spent two hours on this.
Granted, a lot of upvotes will probably be more of an encouragement to the author than saying 'this is worthy of HN', but still.
No, we don't need every tutorial or every Go thread to come up, but this one wasn't so bad.
Edit: Speaking of go have you seen the new OK go video?
$('.some_selector').action();
...
$('.some_selector').anotherAction();OTOH, .action() could change the whole dom so that .some_selector matches something else or nothing at all, so I guess jquery couldn't make that assumption / optimization without knowing what .action() does, or without doing a deep analysis of what DOM elements .action() altered and whether the selector on the next line is affected.
Or needless selectors like $('div.some-div input.some-input') where the classes are never used on anything other than divs/inputs. Another thing I've seen: $('#someId #childId').
Another important part of optimization is profiling. Profiling lets you see where your program is spending the bulk of its time. Then you can make informed decisions about where to direct your efforts.
This went from 131 to 76. The 70% calculation was (start-end)/end. Is this the standard method, because it seems like you would divide by the start timing.
Similar with compression. If a 8kb file becomes 2kb, the compression factor should be 0.25x.
When we say 1.7x faster, what is a fast? How does fastness increase? It's nearly 2 fasts instead of one?
I think the compression sample you gave is much better. Multiply the original file size by the factor to get the new, compressed file size. This is much better than a statistic that I hear a lot about the compression in a columnstore database we use, where everyone says "7-10x compression", because that was published first and is popular.
I'd prefer to see something like your compression example. It took 8 seconds before, and now takes 2. My optimization makes the operation take .25x the time.
The one that bothers me is when people say something got x percent slower.
Sort of like losing the amount of time it takes. If I went from $100 to $50. I would say I lost 50% of my money.
Part of me feels like a 50% performance increase is another way to say that I lost 50% of the time it once took.
This is all subjective on my part.
> Try not to query your database if possible.
Actually this is quite generic and applies to any platform...
Failing that, `EqualFold` may be worth looking at. It expresses the same intent, dunno if it's more or less efficient.