Open sinomoe opened 5 years ago
channel是golang非常好用的特性之一,使用channel时常常会与下面的代码:
channel
for { select { case <-ch1: // some codes case <-ch2: // some codes default: } }
通过for select的方法从两个channel中读取数据,其代码本身是没问题的,但是由于加入了default却引入了性能问题,如果defalut分支中不做任何事,或者无必要逻辑,其实现效果和下面的代码别无二致,但是性能却会大打折扣。
for select
default
defalut
for { select { case <-ch1: // some codes case <-ch2: // some codes } }
下面通过benchmark来说明其具体影响,测试代码如下:
func BenchmarkSelectDefault(b *testing.B) { queue := make(chan struct{}, 1) var consumersReady, allWorkFinished sync.WaitGroup Nconsumer := b.N producer := func() { defer allWorkFinished.Done() consumersReady.Wait() for i := 0; i < Nconsumer; i++ { queue <- struct{}{} } close(queue) } consumer := func(id int) { defer allWorkFinished.Done() consumersReady.Done() for { select { case <-queue: return default: } } } consumersReady.Add(Nconsumer) allWorkFinished.Add(Nconsumer + 1) for i := 0; i < Nconsumer; i++ { go consumer(i) } go producer() allWorkFinished.Wait() } func BenchmarkSelect(b *testing.B) { queue := make(chan struct{}, 1) var consumersReady, allWorkFinished sync.WaitGroup Nconsumer := b.N producer := func() { defer allWorkFinished.Done() consumersReady.Wait() for i := 0; i < Nconsumer; i++ { queue <- struct{}{} } close(queue) } consumer := func(id int) { defer allWorkFinished.Done() consumersReady.Done() for { select { case <-queue: return // default: } } } consumersReady.Add(Nconsumer) allWorkFinished.Add(Nconsumer + 1) for i := 0; i < Nconsumer; i++ { go consumer(i) } go producer() allWorkFinished.Wait() }
两个benchmark的差别仅在于select块中是否有空defalut分支,性能测试结果如下:
select
$ go test -bench=. -v goos: darwin goarch: amd64 BenchmarkSelect-4 1000000 2465 ns/op BenchmarkSelectDefault-4 100 11492657 ns/op
由于defalut语句为空或者其逻辑很短,相当于引入了一个死循环占用了绝大多数CPU时间,导致性能骤降,所以在使用select时,能避免使用defalut就应尽量避免,如果必须要使用defalut`,其内部的逻辑也不应该太少,以免导不必要的致性能损失。
defalut就应尽量避免,如果必须要使用
channel
是golang非常好用的特性之一,使用channel
时常常会与下面的代码:通过
for select
的方法从两个channel
中读取数据,其代码本身是没问题的,但是由于加入了default
却引入了性能问题,如果defalut
分支中不做任何事,或者无必要逻辑,其实现效果和下面的代码别无二致,但是性能却会大打折扣。下面通过benchmark来说明其具体影响,测试代码如下:
两个benchmark的差别仅在于
select
块中是否有空defalut
分支,性能测试结果如下:由于
defalut
语句为空或者其逻辑很短,相当于引入了一个死循环占用了绝大多数CPU时间,导致性能骤降,所以在使用select
时,能避免使用defalut就应尽量避免,如果必须要使用
defalut`,其内部的逻辑也不应该太少,以免导不必要的致性能损失。