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条)

报告相同问题?

悬赏问题

  • ¥15 我想在一个软件里添加一个优惠弹窗,应该怎么写代码
  • ¥15 fluent的在模拟压强时使用希望得到一些建议
  • ¥15 STM32驱动继电器
  • ¥15 Windows server update services
  • ¥15 关于#c语言#的问题:我现在在做一个墨水屏设计,2.9英寸的小屏怎么换4.2英寸大屏
  • ¥15 模糊pid与pid仿真结果几乎一样
  • ¥15 java的GUI的运用
  • ¥15 Web.config连不上数据库
  • ¥15 我想付费需要AKM公司DSP开发资料及相关开发。
  • ¥15 怎么配置广告联盟瀑布流