测试ListQueue效率时奇怪的Go基准[已关闭]

cclgggtu  于 2023-03-21  发布在  Go
关注(0)|答案(1)|浏览(110)

**已关闭。**此问题为not reproducible or was caused by typos。当前不接受答案。

这个问题是由打字错误或无法再重现的问题引起的。虽然类似的问题在这里可能是on-topic,但这个问题的解决方式不太可能帮助未来的读者。
昨天关门了。
Improve this question
我自己写了一个LinkQueue,并为这个结构写了基准测试,然后我发现很奇怪,这个LinkQueue结构的Deque()测试已经进行了半个多小时,还是没有结果。

package main

import (
    "sync"
    "testing"
)

// LinkQueue
type (
    LinkQueue struct {
        root *linkNode
        size int
        lock sync.Mutex
    }
    linkNode struct {
        value interface{}
        next  *linkNode
    }
)

var linkQueue *LinkQueue

func init() {
    linkQueue = new(LinkQueue)
}

// Enqueue Push an element to the queue.
func (l *LinkQueue) Enqueue(v interface{}) {
    l.lock.Lock()
    defer l.lock.Unlock()
    if l.size == 0 {
        l.root = &linkNode{value: v}
    } else {
        node := l.root
        for node.next != nil {
            node = node.next
        }
        node.next = &linkNode{value: v}
    }
    l.size++
}

// Dequeue Remove and return the first element of the queue.
func (l *LinkQueue) Dequeue() interface{} {
    l.lock.Lock()
    defer l.lock.Unlock()
    if l.size == 0 {
        panic("empty")
    }
    v := l.root.value
    l.root = l.root.next
    l.size--
    return v
}

func BenchmarkMyFunction(b *testing.B) {
    for i := 0; i < b.N; i++ {
        b.StopTimer()
        for i := 0; i < b.N; i++ { //use b.N for looping
            linkQueue.Enqueue("test")
        }
        b.StartTimer()
        for i := 0; i < b.N; i++ { //use b.N for looping
            linkQueue.Dequeue()
        }
    }
}

func main() {
    testing.Benchmark(BenchmarkMyFunction)
}

事实上,我曾经试过把测试次数减少到10万次,结果是这样的。

goos: windows
goarch: amd64
pkg: structures/list/queue
cpu: 12th Gen Intel(R) Core(TM) i7-12700H
Benchmark_Link_Dequeue
Benchmark_Link_Dequeue-20       1000000000               0.01013 ns/op
PASS

所以我觉得很奇怪,我已经检查了好几遍代码,但是我还是找不到问题在哪里。而且,Deque()的复杂度是O(1),我认为这段代码不应该运行得那么慢。
看去Playground:https://go.dev/play/p/5Vv21fknKQr

tvokkenx

tvokkenx1#

简单地多次运行代码并不是一个好的基准测试策略。一个更合理、更周到的基准测试:

$ go test queue.go queue_test.go -run=! -bench=. -benchmem -benchtime=5000x
queueLen: 1000
BenchmarkEnqDeq-12  5000  1116462 ns/op  24024 B/op  1001 allocs/op
BenchmarkEnq-12     5000  1093628 ns/op  24024 B/op  1001 allocs/op
BenchmarkDeq-12     5000    24319 ns/op     24 B/op     1 allocs/op
$

queue_test.go

package main

import (
    "fmt"
    "testing"
)

const queueLen = 1000

func init() {
    fmt.Println("queueLen:", queueLen)
}

func BenchmarkEnqDeq(b *testing.B) {
    for i := 0; i < b.N; i++ {
        linkQueue := new(LinkQueue)
        for j := 0; j < queueLen; j++ {
            linkQueue.Enqueue("test")
        }
        for j := 0; j < queueLen; j++ {
            linkQueue.Dequeue()
        }
    }
}

func BenchmarkEnq(b *testing.B) {
    for i := 0; i < b.N; i++ {
        linkQueue := new(LinkQueue)
        for j := 0; j < queueLen; j++ {
            linkQueue.Enqueue("test")
        }
    }
}

func BenchmarkDeq(b *testing.B) {
    for i := 0; i < b.N; i++ {
        linkQueue := new(LinkQueue)
        b.StopTimer()
        for j := 0; j < queueLen; j++ {
            linkQueue.Enqueue("test")
        }
        b.StartTimer()
        for j := 0; j < queueLen; j++ {
            linkQueue.Dequeue()
        }
    }
}

https://go.dev/play/p/w3R8ENK9dcW
queue.go

package main

import (
    "sync"
)

// LinkQueue
type (
    LinkQueue struct {
        root *linkNode
        size int
        lock sync.Mutex
    }
    linkNode struct {
        value interface{}
        next  *linkNode
    }
)

var linkQueue *LinkQueue

func init() {
    linkQueue = new(LinkQueue)
}

// Enqueue Push an element to the queue.
func (l *LinkQueue) Enqueue(v interface{}) {
    l.lock.Lock()
    defer l.lock.Unlock()
    if l.size == 0 {
        l.root = &linkNode{value: v}
    } else {
        node := l.root
        for node.next != nil {
            node = node.next
        }
        node.next = &linkNode{value: v}
    }
    l.size++
}

// Dequeue Remove and return the first element of the queue.
func (l *LinkQueue) Dequeue() interface{} {
    l.lock.Lock()
    defer l.lock.Unlock()
    if l.size == 0 {
        panic("empty")
    }
    v := l.root.value
    l.root = l.root.next
    l.size--
    return v
}

func main(){}

https://go.dev/play/p/KQQN7-CHQhn

相关问题