如何在Go中同步可变数量的频道?

时间:2015-06-18 01:00:53

标签: go

我通过编写一个客户端(以Web服务器的形式)来测试Go中的并发性,该客户端向Web服务器发出许多请求,然后返回发出这些请求所需的时间。基本上是一个基准工具。

以下是我目前正在使用的代码:main.go

我知道我的代码有很多缺陷,但我现在关注的是,如果我添加更多的常规调用,需要花多少精力来测试性能如何变化。在 CallSync 函数中,我必须继续添加到这个庞大的select语句以及启动go例程的func的大量调用列表中。我知道必须有更好的方法。我可能甚至不需要像现在这样同步,但如果我做了,我怎么能以更灵活的方式做到这一点?我希望有代码,我可以指定要调用的“go例程”的数量,它将调用该例程多次并与所有相关通道同步,而不必硬编码。

1 个答案:

答案 0 :(得分:2)

像@JiangYD建议的那样,使用一个频道更容易:

type resp struct {
    id string
    i  int
}

func Async(url string, c chan<- resp, id string, count int) {
    cnt := 0
    for i := 0; i < count; i++ {
        GetPage(url)
        cnt = cnt + 1
        if cnt == 50 {
            c <- resp{id, i}
            cnt = 0
        }
    }
}

func CallSync(w http.ResponseWriter, r *http.Request) {
    t0 := time.Now()
    ch := make(chan resp, 20)
    for i := range [20]struct{}{} {
        go Async("http://localhost:8080/", ch, fmt.Sprintf("ch%02d", i), 2000)
    }
    count := 0
    for count < 4000 {
        select {
        case r := <-ch:
            fmt.Printf("%+v\n", r)
        default:
        }
    }
    t1 := time.Now()
    diff := t1.Sub(t0)
    num := diff.Nanoseconds() / int64(time.Millisecond)
    msec := float64(num) / 1000
    reqsec := float64(count) / msec
    fmt.Fprintf(w, "%v requests\n", count)
    fmt.Fprintf(w, "Performed in %v\n", diff)
    fmt.Fprintf(w, "At a rate of %v (requests/sec)\n", reqsec)
}

另一种方法是使用reflect.Select但这只会减慢速度。