duanneng2014 2013-12-28 10:21
浏览 47
已采纳

Go中的slice元素访问复杂性是什么?

I thought it to be O(1), but this is from a pprof output:

140    140  176:    var lastSB byte = s[lenSMinusOne]
88     88   177:    var lastSuffixB byte = suffix[lenSuffixMinusOne]

and by average length of s is greater than length of suffix. Thus, this shows that accessing an element takes longer if the slice is bigger?

The function is:

func hasSuffix(s, suffix []byte) bool {

    lenSMinusOne      := len(s)      - 1
    lenSuffixMinusOne := len(suffix) - 1

    var lastSB byte = s[lenSMinusOne]
    var lastSuffixB byte = suffix[lenSuffixMinusOne]

    if lenSMinusOne < lenSuffixMinusOne {
        return false
    } else if lastSB != lastSuffixB {
        return false
    } else {
        for i := 0; i < lenSuffixMinusOne ; i++ {
               if suffix[i] != s[lenSMinusOne-lenSuffixMinusOne+i] {
                        return false
               }
        }
    }
    return true
}

UPDATE: To reproduce the results install fetch which uses go-porterstemmer fork with a large corpus(I use a 440mb file).

  • 写回答

2条回答 默认 最新

  • dsa2c2255888 2013-12-28 22:47
    关注

    pprof collects samples during program execution to illuminate hotspots. Use the testing package and go test to run benchmarks.

    As you should expect, the following benchmark shows that there is no difference between reading the 2nd element of a slice on average and reading the 2691st element of a slice on average, 13439773 ns/op versus 13460864 ns/op for 904,061 byte slice elements. Both benchmarks use the same underlying data arrays. Indexing a slice is O(1).

    In your example, you are reading from two different underlying data arrays with different access patterns (outer versus inner loop). On modern processors, which have sophisticated memory management and optimization, you shouldn't expect the same results.

    $ go version
    go version devel +3ae7a530dd4e Sat Dec 28 09:37:54 2013 -0800 linux/amd64
    $ go test -bench=IndexWord
    904061 2 2690.8131199111563
    testing: warning: no tests to run
    PASS
    BenchmarkIndexWordLong       100      13460864 ns/op
    BenchmarkIndexWordShort      100      13439773 ns/op
    ok      bench   7.814s
    $
    

    .

    package main
    
    import (
        "bytes"
        "fmt"
        "io/ioutil"
        "testing"
    )
    
    var (
        Words    [][]byte
        ShortLen = 2
    )
    
    func IndexWord(b *testing.B, words [][]byte) {
        b.ResetTimer()
        b.StartTimer()
        var char byte
        for i := 0; i < b.N; i++ {
            for _, word := range words {
                char = word[len(word)-1]
            }
        }
        _ = char
    }
    
    func BenchmarkIndexWordLong(b *testing.B) {
        words := make([][]byte, len(Words))
        for i, word := range Words {
            words[i] = word
        }
        IndexWord(b, words)
    }
    
    func BenchmarkIndexWordShort(b *testing.B) {
        words := make([][]byte, len(Words))
        for i, word := range Words {
            if len(word) > ShortLen {
                word = word[:ShortLen]
            }
            words[i] = word
        }
        IndexWord(b, words)
    }
    
    func init() {
        // The Complete Works of William Shakespeare
        // http://www.gutenberg.org/cache/epub/100/pg100.txt
        text, err := ioutil.ReadFile(`/home/peter/pg100.txt`)
        if err != nil {
            panic(err)
        }
        var n, short, long int64
        Words = bytes.Fields(text)
        for i, word := range Words {
            word = bytes.Repeat(word, 600) // Requires 4GB memory
            Words[i] = word
            n++
            long += int64(len(word))
            shortLen := ShortLen
            if len(word) < ShortLen {
                shortLen = len(word)
            }
            short += int64(shortLen)
        }
        fmt.Println(n, float64(short)/float64(len(Words)), float64(long)/float64(len(Words)))
    }
    

    The code for your hasSuffix function looks like a direct port from another language; it doesn't look like it is written for Go. Here's my rewrite.

    func hasSuffix(s, suffix []byte) bool {
        if len(s) < len(suffix) {
            return false
        }
        s = s[len(s)-len(suffix):]
        for i, x := range suffix {
            if x != s[i] {
                return false
            }
        }
        return true
    }
    

    Also, Go has a bytes.HasSuffix function.

    Package bytes

    func HasSuffix

    func HasSuffix(s, suffix []byte) bool
    

    HasSuffix tests whether the byte slice s ends with suffix.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效