意外的Go语言切片排序基准测试结果

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

Unexpected benchmark results for slice sorting in Go

问题

我刚开始学习Go语言,并决定实现一些基本的排序算法(冒泡排序、选择排序和插入排序),以尝试使用包、切片和测试基础设施。

以下是实现的代码:

package child_sort

func SortBubble(xs []int) {
    for i := range xs {
        swapped := false
        for j := 1; j < len(xs)-i; j++ {
            if xs[j-1] > xs[j] {
                xs[j-1], xs[j] = xs[j], xs[j-1]
                swapped = true
            }
        }
        if !swapped {
            break
        }
    }
}

func SortSelection(xs []int) {
    for i := range xs {
        min_i := i
        for j := i + 1; j < len(xs); j++ {
            if xs[j] < xs[min_i] {
                min_i = j
            }
        }
        if min_i != i {
            xs[i], xs[min_i] = xs[min_i], xs[i]
        }
    }
}

func SortInsertion(xs []int) {
    for i := 1; i < len(xs); i++ {
        for j := i; j > 0; j-- {
            if xs[j] < xs[j-1] {
                xs[j], xs[j-1] = xs[j-1], xs[j]
            }
        }
    }
}

单元测试似乎工作正常,但是当我为它们创建基准测试时,我得到了奇怪的结果,例如:

go test --bench . --benchmem 
PASS
BenchmarkBubble       1   2258469081 ns/op   241664 B/op   1 allocs/op
BenchmarkSelection    1000000000   0.60 ns/op   0 B/op   0 allocs/op
BenchmarkInsertion       1   1180026827 ns/op   241664 B/op   1 allocs/op
ok   .../go/src/child_sort   12.976s

让我困惑的是,选择排序几乎瞬间运行,并且产生了零次分配。如果我减小数组的大小,其他排序算法也会发生同样的情况。相反,如果我增加大小,选择排序开始表现正常。

以下是测试文件的内容:

package child_sort

import (
    "math/rand"
    "testing"
    "time"
)

func generate(size int, min, max int) []int {
    rand.Seed(time.Now().UTC().UnixNano())
    var xs = make([]int, size, size)
    for i := range xs {
        xs[i] = min + rand.Intn(max-min)
    }
    return xs
}

func TestSortBubble(t *testing.T) {
    xs := []int{9, 8, 7, 6, 5}
    ys := []int{5, 6, 7, 8, 9}
    SortBubble(xs)
    for i, v := range xs {
        if v != ys[i] {
            t.Errorf("fail")
        }
    }
}

func TestSortSelection(t *testing.T) {
    xs := []int{1, 2, 9, 6, 2}
    ys := []int{1, 2, 2, 6, 9}
    SortSelection(xs)
    for i, v := range xs {
        if v != ys[i] {
            t.Errorf("fail")
        }
    }
}

func TestSortInsertion(t *testing.T) {
    xs := []int{1, 2, 9, 6, 2}
    ys := []int{1, 2, 2, 6, 9}
    SortInsertion(xs)
    for i, v := range xs {
        if v != ys[i] {
            t.Errorf("fail")
        }
    }
}

func BenchmarkBubble(b *testing.B) {
    xs := generate(10000, -100, 100)
    /* b.ResetTimer() */
    SortBubble(xs)
}

func BenchmarkSelection(b *testing.B) {
    xs := generate(10000, -100, 100)
    /* b.ResetTimer() */
    SortSelection(xs)
}

func BenchmarkInsertion(b *testing.B) {
    xs := generate(10000, -100, 100)
    /* b.ResetTimer() */
    SortInsertion(xs)
}

希望对你有所帮助!

英文:

I just started learning golang and decided to implement some basic sorting algorithms (bubble sort, selection sort, and insertion sort) to try working with packages, slices, and testing infrastructure.

Here's the implementation:

package child_sort
func SortBubble(xs []int) {
for i := range xs {
swapped := false
for j := 1; j &lt; len(xs)-i; j++ {
if xs[j-1] &gt; xs[j] {
xs[j-1], xs[j] = xs[j], xs[j-1]
swapped = true
}
}
if !swapped {
break
}
}
}
func SortSelection(xs []int) {
for i := range xs {
min_i := i
for j := i + 1; j &lt; len(xs); j++ {
if xs[j] &lt; xs[min_i] {
min_i = j
}
}
if min_i != i {
xs[i], xs[min_i] = xs[min_i], xs[i]
}
}
}
func SortInsertion(xs []int) {
for i := 1; i &lt; len(xs); i++ {
for j := i; j &gt; 0; j-- {
if xs[j] &lt; xs[j-1] {
xs[j], xs[j-1] = xs[j-1], xs[j]
}
}
}
}

Unit tests seem to work fine, but when I created benchmarks for these, I got weird results, like these:

go test --bench . --benchmem 
PASS
BenchmarkBubble	       1	2258469081 ns/op	  241664 B/op	       1 allocs/op
BenchmarkSelection	1000000000	         0.60 ns/op	       0 B/op	       0 allocs/op
BenchmarkInsertion	       1	1180026827 ns/op	  241664 B/op	       1 allocs/op
ok  	.../go/src/child_sort	12.976s

What bugs me is that selection sort runs almost instantly and produces zero allocations. Same thing happens to other sorting algos if I decrease the size of the arrays. And the opposite is true, i.e. if I increase the size, selection sort starts to behave sanely.

Here's the tests file:

package child_sort
import (
&quot;math/rand&quot;
&quot;testing&quot;
&quot;time&quot;
)
func generate(size int, min, max int) []int {
rand.Seed(time.Now().UTC().UnixNano())
var xs = make([]int, size, size)
for i := range xs {
xs[i] = min + rand.Intn(max-min)
}
return xs
}
func TestSortBubble(t *testing.T) {
xs := []int{9, 8, 7, 6, 5}
ys := []int{5, 6, 7, 8, 9}
SortBubble(xs)
for i, v := range xs {
if v != ys[i] {
t.Errorf(&quot;fail&quot;)
}
}
}
func TestSortSelection(t *testing.T) {
xs := []int{1, 2, 9, 6, 2}
ys := []int{1, 2, 2, 6, 9}
SortSelection(xs)
for i, v := range xs {
if v != ys[i] {
t.Errorf(&quot;fail&quot;)
}
}
}
func TestSortInsertion(t *testing.T) {
xs := []int{1, 2, 9, 6, 2}
ys := []int{1, 2, 2, 6, 9}
SortInsertion(xs)
for i, v := range xs {
if v != ys[i] {
t.Errorf(&quot;fail&quot;)
}
}
}
func BenchmarkBubble(b *testing.B) {
xs := generate(10000, -100, 100)
/* b.ResetTimer() */
SortBubble(xs)
}
func BenchmarkSelection(b *testing.B) {
xs := generate(10000, -100, 100)
/* b.ResetTimer() */
SortSelection(xs)
}
func BenchmarkInsertion(b *testing.B) {
xs := generate(10000, -100, 100)
/* b.ResetTimer() */
SortInsertion(xs)
}

答案1

得分: 8

观察到的效果与你的排序代码、切片或其他内容无关。问题在于你没有正确使用b testing.B:你应该执行你的代码b.N次。

看一下标准排序包是如何进行基准测试的:http://golang.org/src/pkg/sort/sort_test.go

英文:

The observed effects have nothing to do with your sorting code, slices or whatever. You are simply not using b testing.B properly: You are supposed to execute your code b.N times.

Have a look at how the standard sorting package does its benchmarks: http://golang.org/src/pkg/sort/sort_test.go

huangapple
  • 本文由 发表于 2014年3月19日 16:45:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/22500407.html
匿名

发表评论

匿名网友

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

确定