1. 7

  2. 12

    There’s now an edit indicating that the comparison is wrong anyhow: The Rust code was parsing the string many more times than Go because of the way the code was written.

    1. 2

      Plus the comparisons were different. Also, the code was a weird mix of looking at bytes and unicode codepoints.

      This sloppy-approach-to-everything is sadly a thing I have started to expect from Go users, and one of the reasons why I automatically penalize projects using Go in terms of quality and reliability unless proven otherwise.

    2. 7

      I think this is encountering some of the pitfalls of micro-benchmarks.

      • It’s not clear whether the Go benchmark framework accounted for GC time. It probably wouldn’t unless the benchmark allocated enough to fill the default heap, or the measurement phase ended with an explicit call to run the GC.
      • IIRC Go’s GC is concurrent, so the Go version is making use of concurrency where the Rust version isn’t. (Which can be seen a a point in favor of Go. But it may be that the Go version uses more CPU time overall, it’s just not being measured.)
      • This code is kind of a perfect case for a scavenging GC because none of the allocated memory persists: it’s all garbage. Also, none of the heap blocks contain pointers, so there’s no time spent tracing through object graphs. All the GC has to do is preserve the one heap block currently In use.
      1. 0

        Go is garbage collected, rust is not. That means rust is faster than go, right? No! Not always.

        Why does it mean that, generally?

        1. 2

          The assumption is that if you have a garbage collector stopping the world a lot, your application is going to run slower. In small benchmarks like this (although this once was broken), it impacts the perceived performance quite a bit. In practice, while it’s debated, languages with GCs do achieve high performance and can achieve similar speeds to manually managed languages. The JVM, Julia, & Go are all great examples of this.

          1. 0

            Yes, GC has costs, but so does reference counting. Making such a blanket statement is just misinformation.

            1. 4

              My (non-expert) understanding is that “gc is slow for managing heap memory” is a misconception, and than in fact the opposite is true – for allocation-heavy workloads modern gc schemes are faster than traditional malloc/free implementations.

              However, languages without tracing/reference counting GC tend to use heap more frugaly in the first place, and that creates the perf difference in real-world programs.

              1. 1

                The Go compiler does escape analysis and can (to some extent) avoid putting things on the heap if they do not have to be.

              2. 3

                But rust doesn’t do reference counting most of the time.

                1. 2

                  Rust only does reference counting when you ask for it by typing Rc, generally yourself.