go 运行时,命令/编译:字符串拼接的性能专用程序集,

yrdbyhpb  于 8个月前  发布在  Go
关注(0)|答案(4)|浏览(212)

CL123256 发起了一场关于我们应该选择哪种字符串拼接特化(如果有的话)的讨论。
如果我们专门针对带有转义结果和参数个数小于等于5(N)的拼接进行优化,那么字符串拼接的速度会更快。转义结果意味着我们可以避免传递始终为 nilbuf ,并使用 rawstring 代替 rawstringtmp 。已知的 N 意味着我们可以展开循环。
有几种方法(这些并不是全部):

  1. 为 N=2 进行特化 x+y 。代码较少,似乎最常见,提升最大,但不会提高其他任何拼接(如使用 concatstring3x+y+z )。
  2. 为所有 N 进行特化,但由于性能提升可能不值得。
  3. 为 N={2,3,4,5} 进行特化。代码较多。
  4. 为 N={2,3} 进行特化,覆盖了大部分拼接。显著提高了 concat2 和 concat3 的速度。
    我从 (1) 开始,因为这是最容易更改的更改,需要较少的更改并带来显著的性能提升。但是为了做出决策,还需要额外的反馈。
    以下是 (1) 与未优化的拼接进行比较的结果:
  1. name old time/op new time/op delta
  2. Concat2-8 74.2ns ± 0% 53.5ns ± 1% -27.95% (p=0.000 n=9+15)
  3. Concat3-8 94.9ns ± 0% 94.8ns ± 0% ~ (p=0.082 n=14+15)
  4. Concat2Empty-8 21.4ns ± 1% 14.2ns ± 0% -33.75% (p=0.000 n=15+14)
  5. Concat3Empty-8 23.9ns ± 1% 23.9ns ± 1% ~ (p=0.756 n=15+15)
  6. [Geo mean] 43.6ns 36.2ns -16.88%

对于 (4) 实现与 go tip 的比较:

  1. name old time/op new time/op delta
  2. Concat2-8 74.2ns ± 0% 66.1ns ± 1% -10.95% (p=0.000 n=9+15)
  3. Concat3-8 94.9ns ± 0% 71.9ns ± 1% -24.22% (p=0.000 n=14+15)
  4. Concat2Empty-8 21.4ns ± 1% 21.1ns ± 0% -1.56% (p=0.000 n=15+15)
  5. Concat3Empty-8 23.9ns ± 1% 16.6ns ± 1% -30.63% (p=0.000 n=15+12)
  6. [Geo mean] 43.6ns 35.9ns -17.61%

请注意,这些数字表示开销节省,而不是一般情况中字符串拼接性能提升,因为字符串长度对这些计时有很大影响。
基准测试:

  1. package foo
  2. import "testing"
  3. //go:noinline
  4. func concat2(x, y string) string {
  5. return x + y
  6. }
  7. //go:noinline
  8. func concat3(x, y, z string) string {
  9. return x + y + z
  10. }
  11. var x = "foor"
  12. var y = "2ews"
  13. var z = ""
  14. func BenchmarkConcat2(b *testing.B) {
  15. for i := 0; i < b.N; i++ {
  16. _ = concat2(x, "abc")
  17. }
  18. }
  19. func BenchmarkConcat3(b *testing.B) {
  20. for i := 0; i < b.N; i++ {
  21. _ = concat3(x, "abc", y)
  22. }
  23. }
  24. func BenchmarkConcat2Empty(b *testing.B) {
  25. for i := 0; i < b.N; i++ {
  26. _ = concat2(x, "")
  27. }
  28. }
  29. func BenchmarkConcat3Empty(b *testing.B) {
  30. for i := 0; i < b.N; i++ {
  31. _ = concat3("", x, z)
  32. }
  33. }

我想了解:

  1. 这种优化是否受欢迎。
  2. 如果需要,我们需要选择采取哪种方法。
    CC @martisch
ebdffaop

ebdffaop1#

СС @TocarIP@josharian@mvdan

eagi6jfj

eagi6jfj2#

仅添加来自CL的数据:

  1. For go executable, there are:
  2. 501 concatstring2
  3. 194 concatstring3
  4. 55 concatstring4
2ledvvac

2ledvvac3#

Kindly paging @randall77@ianlancetaylor in case of some more ideas too

kulphzqa

kulphzqa4#

我并不特别担心额外的代码。如果这意味着为逃逸和非逃逸情况复制 concatstringsconcatstring[2345],那并不是什么大问题。
你是否还计划在 concatstrings 中展开循环?此外,在这里我不担心二进制代码大小,但我担心大量复制粘贴的内部循环体的可维护性。

相关问题