如何在Go语言中同步不同数量的通道?

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

How do I synchronize a variable number of channels in Go?

问题

我正在使用Go语言编写一个客户端(以Web服务器的形式),通过向Web服务器发送多个请求,然后返回完成这些请求所花费的时间,从而测试Go语言中的并发性。基本上是一个基准测试工具。

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

我知道我的代码有很多缺陷,但我目前关注的一个问题是,如果我添加更多的Go协程调用,测试性能将需要多大的工作量。在CallSync函数中,我不得不不断添加到这个庞大的select语句和调用启动Go协程的函数的庞大列表中。我知道肯定有更好的方法。我可能甚至不需要像现在这样同步,但如果我需要,我该如何以更灵活的方式实现呢?我希望能够编写代码,可以指定要调用的“Go协程”数量,并调用该协程指定的次数,并与所有相关的通道进行同步,而不必硬编码所有内容。

英文:

I am testing out concurrency in Go by writing a client (in the form of a web server) that makes many requests to a web server and then returns how long it took to make those requests. Basically a benchmark tool.

Here is to code I am using currently: main.go

I know my code has many flaws but the one I am concerned with at the moment is how much effort it takes test how performance would change if I add more go routine calls. In the CallSync function I have to keep adding on to this massive select statement and to the massive list of calls to the func that starts the go routine. I know there must be a better way. I probably don't even need to synchronize like I am right now, but if I did how could I do this in a more flexible way? I want to have code where I can specify the number of "go routines" to call and it will call that the routine that number of times and synchronize with all the associated channels without having to hard code it all.

答案1

得分: 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,但这只会减慢速度。

英文:

Like @JiangYD suggested, it's easier to just use one channel:

type resp struct {
	id string
	i  int
}

func Async(url string, c chan&lt;- resp, id string, count int) {
	cnt := 0
	for i := 0; i &lt; count; i++ {
		GetPage(url)
		cnt = cnt + 1
		if cnt == 50 {
			c &lt;- 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(&quot;http://localhost:8080/&quot;, ch, fmt.Sprintf(&quot;ch%02d&quot;, i), 2000)
	}
	count := 0
	for count &lt; 4000 {
		select {
		case r := &lt;-ch:
			fmt.Printf(&quot;%+v\n&quot;, 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, &quot;%v requests\n&quot;, count)
	fmt.Fprintf(w, &quot;Performed in %v\n&quot;, diff)
	fmt.Fprintf(w, &quot;At a rate of %v (requests/sec)\n&quot;, reqsec)
}

Another approach is to use reflect.Select but that would just slow things down.

huangapple
  • 本文由 发表于 2015年6月18日 09:00:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/30904885.html
匿名

发表评论

匿名网友

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

确定