golang中benchmark测试如何初始化测试数据?
How to initialize test data for benchmark test in golang?
当我为我的算法写基准测试时,我被一个问题搞糊涂了!
我的测试代码细节被推送到github,我把它复制到这里并添加一些评论。
https://github.com/hidstarshine/Algorithm/blob/master/leet/problem24_test.go
var TDBenchmarkSwapPairs1 *leet.ListNode
// This function may be not good, it should be init()?
func FTDBenchmarkSwapPairs1() {
TDBenchmarkSwapPairs1 = &leet.ListNode{
Val: 0,
Next: nil,
}
changeNode := TDBenchmarkSwapPairs1
for i := 1; i < 100; i++ {
changeNode.Next = &leet.ListNode{
Val: i,
Next: nil,
}
changeNode = changeNode.Next
}
}
func BenchmarkSwapPairs1(b *testing.B) {
FTDBenchmarkSwapPairs1() // problem is here
for i := 0; i < b.N; i++ {
leet.SwapPairs1(TDBenchmarkSwapPairs1)
}
}
在问题行中,我调用了FTDBenchmarkSwapPairs1(FTD表示填充测试数据)来初始化数据。
然后发生了一些令人惊奇的事情,BenchmarkSwapPairs1 似乎在许多 goroutine 中 运行。
因此并发带来了数据竞争,并且由于 SwapPairs1 的特殊逻辑,调试变得一团糟。
SwapPairs1 将更改 ListNode 中的 Next。
那我想把BenchmarkSwapPairs1移动到for的block中来解决这个问题。
但是data race似乎还没有解决,benchmark测试因为初始化的时间问题没有意义
我在 leetcode 上判断算法并被接受!
问:如何优雅地解决这个问题?需要一个好主意!
新@Jimb
我只是添加了一些调试信息然后它就崩溃了。我也觉得一开始不会有data race
看到恐慌就做出了假设!
package leet_test
import (
"fmt"
"testing"
"github.com/hidstarshine/Algorithm/leet"
)
var TDBenchmarkSwapPairs1 *leet.ListNode
func FTDBenchmarkSwapPairs1() {
TDBenchmarkSwapPairs1 = &leet.ListNode{
Val: 0,
Next: nil,
}
changeNode := TDBenchmarkSwapPairs1
for i := 1; i < 100; i++ {
changeNode.Next = &leet.ListNode{
Val: i,
Next: nil,
}
changeNode = changeNode.Next
}
AnotherChangeNode := TDBenchmarkSwapPairs1
for AnotherChangeNode != nil {
fmt.Println(AnotherChangeNode)
AnotherChangeNode = AnotherChangeNode.Next
}
}
func BenchmarkSwapPairs1(b *testing.B) {
FTDBenchmarkSwapPairs1()
for i := 0; i < b.N; i++ {
fmt.Println(TDBenchmarkSwapPairs1.Next)
fmt.Println(TDBenchmarkSwapPairs1.Next.Next)
fmt.Println(TDBenchmarkSwapPairs1.Next.Next.Next)
fmt.Println(TDBenchmarkSwapPairs1.Next.Next.Next.Next)
leet.SwapPairs1(TDBenchmarkSwapPairs1)
}
}
恐慌信息(重要)
more...
&{98 0xc000044ac0}
&{99 <nil>}
&{1 0xc000044270}
&{2 0xc0000444a0}
&{3 0xc0000444c0}
&{4 0xc0000444d0}
Some system info
&{15 0xc000044ae0}
&{2 0xc000044bd0}
&{17 0xc000044b00}
&{4 0xc000044bf0}
&{17 0xc000044ae0}
Unorderd message
<nil>
&{4 0xc000044ae0}
&{2 <nil>}
<nil>
panic: runtime error: invalid memory address or nil pointer dereference // why
[signal 0xc0000005 code=0x0 addr=0x8 pc=0xbefb20]
如果您有多个基准测试函数,您可能不希望它们干扰彼此的数据,因此请使用局部变量而不是(共享)包级变量。
您可以使用 *B.ResetTimer
从总体基准 运行 时间中删除设置时间。
func BenchmarkSwapPairs1(b *testing.B) {
root := &leet.ListNode{
Val: 0,
Next: nil,
}
changeNode := root
for i := 1; i < 10000; i++ {
changeNode.Next = &leet.ListNode{
Val: i,
Next: nil,
}
changeNode = changeNode.Next
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
root = leet.SwapPairs1(root)
}
}
当我为我的算法写基准测试时,我被一个问题搞糊涂了!
我的测试代码细节被推送到github,我把它复制到这里并添加一些评论。
https://github.com/hidstarshine/Algorithm/blob/master/leet/problem24_test.go
var TDBenchmarkSwapPairs1 *leet.ListNode
// This function may be not good, it should be init()?
func FTDBenchmarkSwapPairs1() {
TDBenchmarkSwapPairs1 = &leet.ListNode{
Val: 0,
Next: nil,
}
changeNode := TDBenchmarkSwapPairs1
for i := 1; i < 100; i++ {
changeNode.Next = &leet.ListNode{
Val: i,
Next: nil,
}
changeNode = changeNode.Next
}
}
func BenchmarkSwapPairs1(b *testing.B) {
FTDBenchmarkSwapPairs1() // problem is here
for i := 0; i < b.N; i++ {
leet.SwapPairs1(TDBenchmarkSwapPairs1)
}
}
在问题行中,我调用了FTDBenchmarkSwapPairs1(FTD表示填充测试数据)来初始化数据。
然后发生了一些令人惊奇的事情,BenchmarkSwapPairs1 似乎在许多 goroutine 中 运行。
因此并发带来了数据竞争,并且由于 SwapPairs1 的特殊逻辑,调试变得一团糟。
SwapPairs1 将更改 ListNode 中的 Next。
那我想把BenchmarkSwapPairs1移动到for的block中来解决这个问题。
但是data race似乎还没有解决,benchmark测试因为初始化的时间问题没有意义
我在 leetcode 上判断算法并被接受!
问:如何优雅地解决这个问题?需要一个好主意!
新@Jimb
我只是添加了一些调试信息然后它就崩溃了。我也觉得一开始不会有data race
看到恐慌就做出了假设!
package leet_test
import (
"fmt"
"testing"
"github.com/hidstarshine/Algorithm/leet"
)
var TDBenchmarkSwapPairs1 *leet.ListNode
func FTDBenchmarkSwapPairs1() {
TDBenchmarkSwapPairs1 = &leet.ListNode{
Val: 0,
Next: nil,
}
changeNode := TDBenchmarkSwapPairs1
for i := 1; i < 100; i++ {
changeNode.Next = &leet.ListNode{
Val: i,
Next: nil,
}
changeNode = changeNode.Next
}
AnotherChangeNode := TDBenchmarkSwapPairs1
for AnotherChangeNode != nil {
fmt.Println(AnotherChangeNode)
AnotherChangeNode = AnotherChangeNode.Next
}
}
func BenchmarkSwapPairs1(b *testing.B) {
FTDBenchmarkSwapPairs1()
for i := 0; i < b.N; i++ {
fmt.Println(TDBenchmarkSwapPairs1.Next)
fmt.Println(TDBenchmarkSwapPairs1.Next.Next)
fmt.Println(TDBenchmarkSwapPairs1.Next.Next.Next)
fmt.Println(TDBenchmarkSwapPairs1.Next.Next.Next.Next)
leet.SwapPairs1(TDBenchmarkSwapPairs1)
}
}
恐慌信息(重要)
more...
&{98 0xc000044ac0}
&{99 <nil>}
&{1 0xc000044270}
&{2 0xc0000444a0}
&{3 0xc0000444c0}
&{4 0xc0000444d0}
Some system info
&{15 0xc000044ae0}
&{2 0xc000044bd0}
&{17 0xc000044b00}
&{4 0xc000044bf0}
&{17 0xc000044ae0}
Unorderd message
<nil>
&{4 0xc000044ae0}
&{2 <nil>}
<nil>
panic: runtime error: invalid memory address or nil pointer dereference // why
[signal 0xc0000005 code=0x0 addr=0x8 pc=0xbefb20]
如果您有多个基准测试函数,您可能不希望它们干扰彼此的数据,因此请使用局部变量而不是(共享)包级变量。
您可以使用 *B.ResetTimer
从总体基准 运行 时间中删除设置时间。
func BenchmarkSwapPairs1(b *testing.B) {
root := &leet.ListNode{
Val: 0,
Next: nil,
}
changeNode := root
for i := 1; i < 10000; i++ {
changeNode.Next = &leet.ListNode{
Val: i,
Next: nil,
}
changeNode = changeNode.Next
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
root = leet.SwapPairs1(root)
}
}