为什么Go语言中的strings.Fields(str)和strings.Split(str, ” “)如此慢?

huangapple go评论122阅读模式
英文:

Why are Go's strings.Fields(str) and strings.Split(str, " ") so slow?

问题

我一直在测试Node和Go中的函数以比较它们的性能。在几乎每个测试中,Go比Node快得多,除非使用strings.Fields()strings.Split(),此时Node的速度是Go的2-3倍。

Go(2.14秒):

start := time.Now()
var newWords []string
str := "asd asjhfa lsjdhalsdjhfa dhfald hfaljdh faldhfasjdhfalsdh asd alsdh alksdh alksdh alksd alkjsd fadlkj dalkjdh asdhfef afa d6a 5a85dfa s5da5d ad a6sd58ad5a8sd5f 8as5f as5 a8s5 8as6d5 8asd65f8as6d58 a5sd 8a5ds8f7 a6s5d"

for j := 0; j < 1000000; j++ {
    words := strings.Split(str, " ")
    wordsLen := len(words)
    newWords = nil
    for i := 0; i < wordsLen; i++ {
        if words[i][:1] != "s" {
            newWords = append(newWords, words[i])
        }
    }
}
dur := time.Since(start)

fmt.Println(newWords)
fmt.Println(dur)

Node(847毫秒):

let start = new Date()
let newWords = []
let str = "asd asjhfa lsjdhalsdjhfa dhfald hfaljdh faldhfasjdhfalsdh asd alsdh alksdh alksdh alksd alkjsd fadlkj dalkjdh asdhfef afa d6a 5a85dfa s5da5d ad a6sd58ad5a8sd5f 8as5f as5 a8s5 8as6d5 8asd65f8as6d58 a5sd 8a5ds8f7 a6s5d"

for (let j = 0; j < 1000000; j++) {
    let words = str.split(" ")
    let wordsLen = words.length
    newWords = []
    for (let i = wordsLen - 1; i >= 0; i--) {
        if (words[i].substr(0, 1) !== "s") {
            newWords.push(words[i])
        }
    }
}

console.log((new Date() - start) + 'ms')
英文:

I have been testing functions in Node and Go to compare their performance. In almost every test, Go is much faster than Node, except when strings.Fields() or strings.Split() is used, then Node is 2-3 times as fast.

Go (2.14s):

start := time.Now()
var newWords []string
str := &quot;asd asjhfa lsjdhalsdjhfa dhfald hfaljdh faldhfasjdhfalsdh asd alsdh alksdh alksdh alksd alkjsd fadlkj dalkjdh asdhfef afa d6a 5a85dfa s5da5d ad a6sd58ad5a8sd5f 8as5f as5 a8s5 8as6d5 8asd65f8as6d58 a5sd 8a5ds8f7 a6s5d&quot;

for j := 0; j &lt; 1000000; j++ {
    words := strings.Split(str, &quot; &quot;)
    wordsLen := len(words)
    newWords = nil
    for i := 0; i &lt; wordsLen; i++ {
        if words[i][:1] != &quot;s&quot; {
            newWords = append(newWords, words[i])
        }
    }
}
dur := time.Since(start)

fmt.Println(newWords)
fmt.Println(dur)

Node (847ms):

let start = new Date()
let newWords = []
let str = &quot;asd asjhfa lsjdhalsdjhfa dhfald hfaljdh faldhfasjdhfalsdh asd alsdh alksdh alksdh alksd alkjsd fadlkj dalkjdh asdhfef afa d6a 5a85dfa s5da5d ad a6sd58ad5a8sd5f 8as5f as5 a8s5 8as6d5 8asd65f8as6d58 a5sd 8a5ds8f7 a6s5d&quot;

for (let j = 0; j &lt; 1000000; j++) {
    let words = str.split(&#39; &#39;)
    let wordsLen = words.length
    newWords = []
    for (let i = wordsLen - 1; i &gt;= 0; i--) {
        if (words[i].substr(0, 1) !== &#39;s&#39;) {
            newWords.push(words[i])
        }
    }
}

console.log((new Date() - start) + &#39;ms&#39;)

答案1

得分: 1

首先,让我们运行你的测试。

$ go run travis.go
5.892531292秒
$ node travis.js
4065毫秒
$

Go花费了5.89秒,而Node.js花费了4.07秒。

其次,让我们运行一个Go基准测试,看看你真正在做什么。它比你在原始帖子中提到的strings.Fields(str)strings.Split(str, " ")要复杂得多。

travis_test.go:

package main

import (
	"strings"
	"testing"
)

var str = "asd asjhfa lsjdhalsdjhfa dhfald hfaljdh faldhfasjdhfalsdh asd alsdh alksdh alksdh alksd alkjsd fadlkj dalkjdh asdhfef afa d6a 5a85dfa s5da5d ad a6sd58ad5a8sd5f 8as5f as5 a8s5 8as6d5 8asd65f8as6d58 a5sd 8a5ds8f7 a6s5d"

func Travis() {
	var newWords []string
	for j := 0; j < 1000000; j++ {
		words := strings.Split(str, " ")
		wordsLen := len(words)
		newWords = nil
		for i := 0; i < wordsLen; i++ {
			if words[i][:1] != "s" {
				newWords = append(newWords, words[i])
			}
		}
	}
}

func BenchmarkTravis(b *testing.B) {
	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		Travis()
	}
	b.StopTimer()
}

输出:

$ go test -run=! -bench=Travis travis_test.go 
goos: linux
goarch: amd64
BenchmarkTravis-4   1   5832192616 ns/op   1488002816 B/op   7000015 allocs/op
PASS
ok  	command-line-arguments	5.838s
$
英文:

First, let's run your tests.

$ go run travis.go
5.892531292s
$ node travis.js
4065ms
$

Go 5.89 seconds versus Node.js 4.07 seconds.

Second, let's run a Go benchmark and see what you are really doing. It's a lot more than the strings.Fields(str) or strings.Split(str, &quot; &quot;) that you said in your original post.

travis_test.go:

package main

import (
	&quot;strings&quot;
	&quot;testing&quot;
)

var str = &quot;asd asjhfa lsjdhalsdjhfa dhfald hfaljdh faldhfasjdhfalsdh asd alsdh alksdh alksdh alksd alkjsd fadlkj dalkjdh asdhfef afa d6a 5a85dfa s5da5d ad a6sd58ad5a8sd5f 8as5f as5 a8s5 8as6d5 8asd65f8as6d58 a5sd 8a5ds8f7 a6s5d&quot;

func Travis() {
	var newWords []string
	for j := 0; j &lt; 1000000; j++ {
		words := strings.Split(str, &quot; &quot;)
		wordsLen := len(words)
		newWords = nil
		for i := 0; i &lt; wordsLen; i++ {
			if words[i][:1] != &quot;s&quot; {
				newWords = append(newWords, words[i])
			}
		}
	}
}

func BenchmarkTravis(b *testing.B) {
	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i &lt; b.N; i++ {
		Travis()
	}
	b.StopTimer()
}

Output:

$ go test -run=! -bench=Travis travis_test.go 
goos: linux
goarch: amd64
BenchmarkTravis-4   1   5832192616 ns/op   1488002816 B/op   7000015 allocs/op
PASS
ok  	command-line-arguments	5.838s
$

huangapple
  • 本文由 发表于 2017年5月29日 22:14:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/44244636.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定