Hacker News new | past | comments | ask | show | jobs | submit login

> The problem with all this is that performance optimization is nothing without measurement.

Not what I'm arguing. I agree. When making code go fast, you should do it in terms of what the profiler tells you to fix.

However, when you are writing code, it is not wasted time to use the right data structures for the problem.

I've literally seen code like this

  public void addItem(List<Foo> foo, Foo item) {
    if (!foo.contains(item)) {
      foo.add(item);
    }
  }
Is that code easier to read or understand than

  Set<Foo> foo = new HashSet<>();
  foo.add(item);
No (and that's the change I made).

I contend that the earlier version was bad code. The dev wasn't thinking about runtime efficiency, they just liked lists and kept using them. This kind of thinking is fairly common (particularly with young devs that aren't familiar with what's available).

And this is where the "No, never ever think about performance while writing code" that you are espousing is, IMO, detrimental to the craft. It is a basic question "Is there a data structure that meets the need of this code" that "PREMATURE OPTIMIZATION EVIL!!!!!" gets in the way of that sort of consideration.

It's sloppy development work.

The only time you SHOULD do the first solution is when you've found that in a tight loop where this method is called the items are limited and cache consistency ends up trumping algorithmic complexity. That is, data should back using a n^2 algorithm over an n algorithm, not the other way around. Especially when the difference in both solutions is a different datastructure.

But further, the code's intent is clearer in the second solution. So it's not only (generally) faster, it also does a better job of communicating intent with future developers. win-win.

I hate that so many devs cargo cult here.

The full quote is

> Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

Knuth wrote that in an era when premature optimization meant breaking out some hand crafted assembly which obscured the intent of the optimization. He was not talking about optimizations which improve debugging and maintenance. He was talking about improvements like TFA OP posted.

The optimizations I'm talking about I do not call "premature". Just like it's not premature to use the SDKs sort function vs your own bubble sort implementation because "oh, don't prematurely optimize!". An optimization that makes code easier to maintain and debug is never premature.




> And this is where the "No, never ever think about performance while writing code" that you are espousing is, IMO, detrimental to the craft.

That’s not my position. I think we broadly agree. I believe most software that is fast was designed fast. And the way you get there is by understanding your problem space well, and benchmarking with real world data as you build. There are almost always ways to take advantage of knowledge of the data to make your code faster.

As an example, in some performance sensitive rust code I’m working on, I have a lot of sets of numbers. The sets are tiny - most of them only contain 1 element. 95% have 1 or 2 elements. I could use HashSet, but instead I’m using SmallVec<[usize; 2]> - which inlines up to 2 items in a list. It’s uglier and more complicated, but in this case it is much faster than the alternative. I know to use this approach because I know my input data.

I agree with other commenters in this thread. Big-O analysis is often misleading. It leads you to pick a good algorithm, but often at the expense of optimizations that could give you 1-2 orders of magnitude better performance if you go looking for them. Things like cache aware memory layouts, reducing allocations via arena allocators and object pools, SIMD, and fast paths in complex functions for common calls.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: