Testing 在golang中测试函数

Testing 在golang中测试函数,testing,go,Testing,Go,所以我决定在golang中为我的函数编写测试。函数本身如下所示: func Insert(slice []int, element int, index int) []int { n := len(slice) slice = slice[:(n + 1)] for i := index; i < n; i++ { slice[i+1] = slice[i] } slice[index] = element return sl

所以我决定在
golang
中为我的函数编写测试。函数本身如下所示:

func Insert(slice []int, element int, index int) []int {
    n := len(slice)
    slice = slice[:(n + 1)]
    for i := index; i < n; i++ {
        slice[i+1] = slice[i]
    }
    slice[index] = element
    return slice
} 
type Slice struct {
    contents []interface{}
    length   int
    capacity int
}
然后f.e
array=Insert(array,1,len(array)/2
。现在我写了
Insert\u test.go

package sdizo

import "testing"

func benchmarkInsert(size int, b *testing.B) {  
    b.ResetTimer()
    for n := 0; n < b.N; n++ {
        array := make([]int, size, size+1)
        array = Insert(array, 1, len(array)/2)
    }
}
func BenchmarkInsert10k(b *testing.B) { benchmarkInsert(10000, b) }
func BenchmarkInsert20k(b *testing.B) { benchmarkInsert(20000, b) }
func BenchmarkInsert30k(b *testing.B) { benchmarkInsert(30000, b) }
func BenchmarkInsert40k(b *testing.B) { benchmarkInsert(40000, b) }
func BenchmarkInsert50k(b *testing.B) { benchmarkInsert(50000, b) }
package-sdizo
导入“测试”
func benchmarkInsert(size int,b*testing.b){
b、 重置计时器()
对于n:=0;n
问题是,在测试循环中有两个操作。我不能将
make()
移动到循环上方,因为每次它尝试插入一些东西时都必须创建一个新数组(不想影响容量)。它工作正常,它会给我输出,但我很好奇这
make()
不会影响时间测量,我想问您,我是否可以仅为
Insert()测量时间


有没有一种方便的方法将基准测试的结果记录到一个文件中?

编辑:你寻找的真实答案。(最后)

当您进行基准测试时,实际上要对您想要进行基准测试的内容进行基准测试。您的用例不会是make,然后每次插入,所以只需进行一次,然后在循环中测试插入。关键是只测试阻塞点

这里要做的就是测试
Insert
。您只需每次调整数组的大小即可,其成本基本上是零(至少与
make
Insert
相比)

使用
array=array[0:size]
执行调整其大小的操作类似于设置结构的
length=size
。请参阅

至于将结果写入文件,这取决于您的操作系统。在任何Unix系统上,只需在最后运行带有
>file.txt
的基准命令,结果就会通过管道传输到
file.txt
。对于Windows不确定

编辑:添加更多测试将显示此项线性扩展

BenchmarkInsert10k-8          200000          7889 ns/op
BenchmarkInsert20k-8          100000         16131 ns/op
BenchmarkInsert30k-8          100000         24184 ns/op
BenchmarkInsert40k-8           50000         31767 ns/op
BenchmarkInsert50k-8           50000         39721 ns/op
BenchmarkInsert100k-8          20000         79711 ns/op
BenchmarkInsert200k-8          10000        159411 ns/op
BenchmarkInsert300k-8           5000        237188 ns/op
BenchmarkInsert400k-8           5000        316270 ns/op
BenchmarkInsert500k-8           3000        399146 ns/op
BenchmarkInsert1000k-8          2000        793845 ns/op
使用此代码:

例如(从Go 1.7开始),使用
插入算法

package sdizo

import (
    "strconv"
    "testing"
)

func Insert(slice []int, element int, index int) []int {
    n := len(slice)
    slice = slice[:(n + 1)]
    for i := index; i < n; i++ {
        slice[i+1] = slice[i]
    }
    slice[index] = element
    return slice
}

func BenchmarkInsert(b *testing.B) {
    for size := 10000; size <= 50000; size += 10000 {

        b.Run(strconv.Itoa(size/1000)+"k",

            func(b *testing.B) {
                a := make([]int, size, size+1)
                b.ReportAllocs()
                b.ResetTimer()
                for i := 0; i < b.N; i++ {
                    a = a[:size]
                    a = Insert(a, 1, len(a)/2)
                }
                b.StopTimer()
            },
        )
    }
}
现在我们可以对您的
Insert
算法进行基准测试,我们可以利用这些知识改进算法。例如

package sdizo

import (
    "strconv"
    "testing"
)

func Insert(slice []int, element int, index int) []int {
    slice = slice[:len(slice)+1]
    copy(slice[index+1:], slice[index:])
    slice[index] = element
    return slice
}

func BenchmarkInsert(b *testing.B) {
    for size := 10000; size <= 50000; size += 10000 {

        b.Run(strconv.Itoa(size/1000)+"k",

            func(b *testing.B) {
                a := make([]int, size, size+1)
                b.ReportAllocs()
                b.ResetTimer()
                for i := 0; i < b.N; i++ {
                    a = a[:size]
                    a = Insert(a, 1, len(a)/2)
                }
                b.StopTimer()
            },
        )
    }
}

以这种方式实现函数有点古怪:现在你依赖调用方提供足够大的切片,否则就会惊慌失措。我知道,但我如何才能使它不同,使它工作?更快,但这不是不正确吗?我认为你的
追加
应该在
元素
分配到
pre[index]之前进行
。你是对的,它仍然引用片中相同的元素。我现在修复了它。必须分配一个新的元素,这会减慢速度。但是,这个技巧的速度大约是我的两倍……不幸的是,它没有我原来想的那么酷。@PaulHankin好的,现在它超级快速和正确。如果我不能使用append呢(必须自己做每一个算法)。顺便说一句,我检查了你的版本,速度更快,但图表看起来是这样的(大概是一条直线)。我的意思是,你得到的数据足够好了,我猜(倍数越大x2,x1.5,x1.33,x1.25),但在我的情况下不是。你不知怎么改变了测试吗?@Edit,好吧,我在Windows上测试了它,它运行得非常好,我想我将不得不在VM上告别Linux:(我的一个编辑有一个更快的算法:P.哈哈,对不起,只是开玩笑。OP无论如何都不会进行优化,所以我从我的答案中删除了杂乱无章的内容。
package sdizo

import (
    "strconv"
    "testing"
)

func Insert(slice []int, element int, index int) []int {
    n := len(slice)
    slice = slice[:(n + 1)]
    for i := index; i < n; i++ {
        slice[i+1] = slice[i]
    }
    slice[index] = element
    return slice
}

func BenchmarkInsert(b *testing.B) {
    for size := 10000; size <= 50000; size += 10000 {

        b.Run(strconv.Itoa(size/1000)+"k",

            func(b *testing.B) {
                a := make([]int, size, size+1)
                b.ReportAllocs()
                b.ResetTimer()
                for i := 0; i < b.N; i++ {
                    a = a[:size]
                    a = Insert(a, 1, len(a)/2)
                }
                b.StopTimer()
            },
        )
    }
}
$ go test -bench=.
goos: linux
goarch: amd64
pkg: sdizo
BenchmarkInsert/10k-4         50000      32502 ns/op       0 B/op      0 allocs/op
BenchmarkInsert/20k-4         20000      64364 ns/op       0 B/op      0 allocs/op
BenchmarkInsert/30k-4         20000      97310 ns/op       0 B/op      0 allocs/op
BenchmarkInsert/40k-4         10000     129196 ns/op       0 B/op      0 allocs/op
BenchmarkInsert/50k-4         10000     161427 ns/op       0 B/op      0 allocs/op
PASS
ok      so/sdizo    9.778s
$ 
package sdizo

import (
    "strconv"
    "testing"
)

func Insert(slice []int, element int, index int) []int {
    slice = slice[:len(slice)+1]
    copy(slice[index+1:], slice[index:])
    slice[index] = element
    return slice
}

func BenchmarkInsert(b *testing.B) {
    for size := 10000; size <= 50000; size += 10000 {

        b.Run(strconv.Itoa(size/1000)+"k",

            func(b *testing.B) {
                a := make([]int, size, size+1)
                b.ReportAllocs()
                b.ResetTimer()
                for i := 0; i < b.N; i++ {
                    a = a[:size]
                    a = Insert(a, 1, len(a)/2)
                }
                b.StopTimer()
            },
        )
    }
}
$ go test -bench=.
goos: linux
goarch: amd64
pkg: sdizo
BenchmarkInsert/10k-4        200000       7664 ns/op       0 B/op      0 allocs/op
BenchmarkInsert/20k-4        100000      15208 ns/op       0 B/op      0 allocs/op
BenchmarkInsert/30k-4        100000      22959 ns/op       0 B/op      0 allocs/op
BenchmarkInsert/40k-4         50000      35181 ns/op       0 B/op      0 allocs/op
BenchmarkInsert/50k-4         50000      39658 ns/op       0 B/op      0 allocs/op
PASS
ok      so/sdizo    10.331s
$