Go 中 t-digest 数据结构的线程安全实现?

我正在尝试在 Go 中运行一个函数的基准测试,如果更多的 goroutine 同时调用它,我怀疑它会减慢速度。我想在基准测试期间捕获函数调用的 P50 和 P95 延迟,例如,使用 ,github.com/influxdata/tdigest如下所示:


package main


import (

    "fmt"

    "math/rand"

    "sync"

    "testing"

    "time"


    "github.com/influxdata/tdigest"

)


func BenchmarkSomething(b *testing.B) {

    concurrencies := []int{1, 10, 30}

    total := 1000


    for _, concurrency := range concurrencies {

        b.Run(fmt.Sprintf("concurrency_%d", concurrency), func(b *testing.B) {

            td := tdigest.New()

            for i := 0; i < b.N; i++ {

                send := make(chan struct{}, total)

                var wg sync.WaitGroup

                for i := 0; i < concurrency; i++ {

                    wg.Add(1)

                    go func() {

                        for range send {

                            start := time.Now()

                            duration := time.Duration(int64(rand.NormFloat64()*1e6)) + time.Millisecond

                            time.Sleep(time.Duration(duration))

                            td.Add(float64(time.Since(start)), 1)

                        }

                    }()

                }


                for i := 0; i < total; i++ {

                    send <- struct{}{}

                }

                close(send)

            }

            b.Log("P50 latency:", td.Quantile(0.50))

        })

    }

}

但是,如果我尝试运行它,我会收到一个index out of range错误:


> go test -bench .

goos: darwin

goarch: amd64

pkg: github.com/kurtpeek/send-closed-channel

BenchmarkSomething/concurrency_1-8          panic: runtime error: index out of range


我怀疑从多个 goroutine 调用这个函数是不安全的?有没有办法获得线程安全的估计器?


繁花如伊
浏览 164回答 1
1回答

慕桂英546537

在高层次上,我通过将问题分为两个步骤来解决这个问题:将延迟发送到缓冲通道(在这种情况下,所需的缓冲区大小是预先知道的),然后调用td.Add()结果。这避免了并发调用td.Add(),同时仍然实现了在并发设置中测量延迟的预期结果。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go