Unsafe string pointers in Go

I created these benchmarks for an article in Norwegian:

I gained some insight into this while writing this. I’m not sure how portable the unsafe-package in Go is, but I did some tests, and there are about 10% to save (deliberately not saying what to save) by doing unsafe []byte to string conversion of some vital parts of Hugo. It might not be worth it (too unsafe), but it’s interesting.

Also have a look at the “memory free” string append to []byte. Got that from a tweet.

1 Like

FYI, Opposite action (convert string into []byte) optimization is merged into Go mainline at https://github.com/golang/go/commit/71be0138421012d04e06991d37d19c9f5b1fa02b.

And the similar optimization on converting []byte to string is also merged at https://github.com/golang/go/commit/e6fac08146df323eb95f46508bef937cdfb802fd

1 Like

Thanks, @tatsushid. But as I read it, the first is range specific, the second is limited to 32 bytes.

Yes, you are right. Merged ones are used in a limited situation. I compared your benchmark in both 1.4.2 and master on my machie

unsafestrings $ ~/Devel/golang/bin/benchcmp 1.4.2.txt master.txt
benchmark                            old ns/op     new ns/op     delta
BenchmarkSafeBytesToString           126           70.0          -44.44%
BenchmarkUnsafeBytesToString         0.88          0.90          +2.27%
BenchmarkUnsafeStringsReplacer       240           269           +12.08%
BenchmarkSafeStringsReplacer         397           339           -14.61%
BenchmarkMultipleBytesReplace        1278          803           -37.17%
BenchmarkMultiplesStringsReplace     1423          1023          -28.11%
BenchmarkAppendString                4.07          4.16          +2.21%
BenchmarkAppendByteString            56.2          14.8          -73.67%

benchmark                            old allocs     new allocs     delta
BenchmarkSafeBytesToString           1              1              +0.00%
BenchmarkUnsafeBytesToString         0              0              +0.00%
BenchmarkUnsafeStringsReplacer       0              0              +0.00%
BenchmarkSafeStringsReplacer         1              1              +0.00%
BenchmarkMultipleBytesReplace        9              3              -66.67%
BenchmarkMultiplesStringsReplace     6              6              +0.00%
BenchmarkAppendString                0              0              +0.00%
BenchmarkAppendByteString            1              0              -100.00%

benchmark                            old bytes     new bytes     delta
BenchmarkSafeBytesToString           48            48            +0.00%
BenchmarkUnsafeBytesToString         0             0             +0.00%
BenchmarkUnsafeStringsReplacer       0             0             +0.00%
BenchmarkSafeStringsReplacer         48            48            +0.00%
BenchmarkMultipleBytesReplace        200           144           -28.00%
BenchmarkMultiplesStringsReplace     288           288           +0.00%
BenchmarkAppendString                0             0             +0.00%
BenchmarkAppendByteString            8             0             -100.00%

It improves the result but unsafe case is still faster than safe case.

Using unsafe would improve the performance but we should take care to keep an original string or []byte is there, not to be collected by GC while using it and also to ensure not to be modified by the other goroutine.

I think using it with function local vars is safe.

1 Like