Channel,Select与GOMAXPROCS

一,Channels

声明后初始化一个无缓冲的channel:

var dataStream chan interface{}

dataStream = make(chan interface{})

将 "<-"  放在chan左边, 声明后初始化一个只读channel:

var dataStream <-chan interface{}

dataStream := make(<-chan interface{})

将 "<-" 放在chan右边, 声明后初始化一个只写channel:

var dataStream chan<- interface{}

dataStream := make(chan<- interface{})


channel类型赋值:

var receiveChan <-chan interface{}

var sendChan chan<- interface{}

dataStream := make(chan interface{})


 //有效的操作:

receiveChan = dataStream     

sendChan = dataStream


从只写channel中读数据:

writeStream := make(chan<- interface{})

<-writeStream

//输出:

    invalid operation: <-writeStream (receive from send-only type chan<-inteface{})


向只读channel中发送数据:

readStream := make(<-chan interface{})

readStream <- struct{}{}

//输出:

    invalid operation: readStream <- struct {} literal (send to receive-only type <-chan interface {})


close用法:

intStream := make(chan int)

close(intStream)
integer, ok := <- intStream 

fmt.Printf("(%v): %v", ok, integer)

//输出:

(false): 0

我们仍然可以从colse的channel中读取值,返回的是类型零值。


close方法常见应用例子:

1),

intStream := make(chan int)
go func() {
  defer close(intStream)
  for i := 1; i <= 5; i++ {
     intStream <- i
  }
}()
for integer := range intStream {
  fmt.Printf("%v ", integer)

}

//输出:

1 2 3 4 5

发送完所有数据 defer close掉,for range 结束


2),

begin := make(chan interface{})
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
  wg.Add(1)
  go func(i int) {
     defer wg.Done()
     <-begin
//阻塞住goroutine
     fmt.Printf("%v has begun\n", i)
  }(i)
}
fmt.Println("Unblocking goroutines...")
close(begin)
//同时解锁所有goroutine

wg.Wait()


读nil通道:

var dataStream chan interface{}

<-dataStream

写nil通道:

var dataStream chan interface{}

dataStream <- struct{}{}

都会死锁:

fatal error: all goroutines are asleep - deadlock!


注意⚠:

close 值为nil的channel会panic:

var dataStream chan interface{}

close(dataStream)


panic: close of nil channel


channel上面常用操作及相应结果:

如上表:我们有三种操作可以导致goroutine阻塞三种操作会导致程序panic!


二,Select

select 可以安全的将channels与诸如取消、超时、等待和默认值之类的概念结合在一起。

select看起来就像switch 包含了很多case,然而与switch不同的是:select块中的case语句没有顺序地进行测试,如果没有满足任何条件,执行不会自动失败,如果同时满足多个条件随机执行一个case。

示例:

c1 := make(chan interface{})
close(c1)
c2 := make(chan interface{})
close(c2)
var c1Count, c2Count int
for i := 1000; i >= 0; i-- {
  select {
  case <-c1:
     c1Count++
  case <-c2:
     c2Count++
  }
}
fmt.Printf("c1Count: %d\nc2Count: %d\n", c1Count, c2Count)

//输出:

c1Count: 466

c2Count: 535


select为什么会随机?

go runtime无法了解select语句的意图,也就是说不能推断出你的问题空间或者为什么你将一组channels 放进一个select语句,所以运行时所能做的最好的事情就是在平均情况下运行良好。通过加权平均每个channel被使用的机会。


三,GOMAXPROCS

这是runtime里面的一个函数,名字有误导性,大家通常认为这个函数与机器的逻辑CPU有关,但实际上这个函数控制的OS线程的数量将承载所谓的“工作队列”,在1.5之前,GOMAXPROCS总是被设置为1.

runtime.GOMAXPROCS(runtime.NumCPU())

通常地开发人员需要利用机器上所有内核,所以在随后的版本中它自动的设置成逻辑CPU的数量。


为什么要调整这个值?

例如,我在一个项目上工作,这个项目有一个测试套件,它被race 条件所困扰。不管怎么说,这个团队有几个测试包,有些测试失败了。我们运行测试的基础结构只有四个逻辑cpu,因此在任何一个点上,我们都有四个goroutines同时执行。通过增加GOMAXPROCS超过我们拥有的逻辑cpu数量,我们能够更频繁地触发竞争条件,从而更快地纠正它们。



©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容