Go|Go 语言圣经 8.4 Channels

8.4 Channels 知识点

  • 1.goroutine是Go语言程序的并发体的话,channels则是它们之间的通信机制
  • 2.一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息
  • 3.channel的零值也是nil
  • 4.两个相同类型的channel可以使用==运算符比较,同样可以和nil比较
  • 5.channel有发送和接受两个主要操作,都是通信行为
  • 6.<- channel在左侧是发送,在右侧是接收,不使用接收数据操作符也是合法的
  • 7.如果channel被关闭,则任何发送操作都会导致panic异常, 但是依然能接收到成功发送的数据,如果没有数据,则产生零值数据
  • 8.channel的make创建第二个参数,对应其容量
  • 9.无缓存Channels的发送和接收操作将导致两个goroutine做一次同步操作,因此被称为同步Channels
  • 10.happens before
  • 11.一个Channel的输出作为下一个Channel的输入, 这种串联的Channels就是所谓的管道(pipeline)
  • 12.串行的channel是无法知道另一个channel是否关闭的,
  • 但是关闭的channel会产生第二个值,为bool类型,ture代表接收到值,false表示channel已被关闭没有可接收的值
  • 13.带缓存的channel内部有一个元素队列,容量在创建时通过第二个参数指定
  • 14.带缓存channel会因为队列满导致发送等待,队列空接收等待
  • 15.发送的内容添加到队列尾部,接收内容是从队列头部取出并删除
代码
func test_Channels(){//演示在netcat的channel_84 //test_echo()//串行channel //test_pipeline()//使用单向channel实现串行 //单向操作的channel中的只接受方是不需要关闭的,发送者关闭即可 //任何双向channel向单向channel变量的赋值操作都将导致该隐式转换 //naturals := make(chan int) //squares := make(chan int) //go counter_chan(naturals) //go squarer(squares, naturals) //printer(squares)//带缓存channel test_channel_cache() }func test_pipeline(){ naturals := make(chan int) squares := make(chan int)max := 100// Counter go func() { for x := 0; ; x++{ if x > max { close(naturals) break } naturals <- x } }()// Squarer go func() { for { x, ok := <- naturals if !ok { fmt.Println("naturals close") break } squares <- x * x } close(squares) }()// Printer (in main goroutine) for { x, ok := <-squares if !ok { fmt.Println("squares close") break } fmt.Println(x) } } func counter_chan(out chan<- int) { for x := 0; x < 100; x++ { out <- x } close(out) }func squarer(out chan<- int, in <-chan int) { for v := range in { out <- v * v } close(out) }func printer(in <-chan int) { for v := range in { fmt.Println(v) } } func test_channel_cache(){ chan_cache := make(chan string, 3) //channel缓存容量 fmt.Println(cap(chan_cache))chan_cache <- "A" chan_cache <- "B" chan_cache <- "C" //有效元素个数 fmt.Println(len(chan_cache))fmt.Println(<-chan_cache) // "A" //有效元素个数 fmt.Println(len(chan_cache))chan_cache <- "AA" //有效元素个数 fmt.Println(len(chan_cache))fmt.Println(<-chan_cache) // "B" fmt.Println(<-chan_cache) // "C" //有效元素个数 fmt.Println(len(chan_cache))result := mirroredQuery() fmt.Println(result) } func mirroredQuery() string { responses := make(chan string, 3) go func() { responses <- request("asia.gopl.io") }() go func() { responses <- request("europe.gopl.io") }() go func() { responses <- request("americas.gopl.io") }() /* 练习 8.11: 紧接着8.4.4中的mirroredQuery流程, 实现一个并发请求url的fetch的变种。 当第一个请求返回时,直接取消其它的请求。 ----添加一个select,来终止goroutine */ select { case <-done: return "终止成功" case <-responses: return <-responses } } func request(hostname string) (response string) { if hostname == "asia.gopl.io" { time.Sleep(1 * time.Second) return "111" }else if hostname == "europe.gopl.io" { time.Sleep(2 * time.Second) return "222" }else if hostname == "americas.gopl.io" { time.Sleep(500 * time.Millisecond) return "333" } return "000" }

——不足之处,欢迎补充—— 备注 《Go 语言圣经》
  • 学习记录所使用的GO版本是1.8
  • 学习记录所使用的编译器工具为GoLand
  • 学习记录所使用的系统环境为Mac os
  • 学习者有一定的C语言基础
【Go|Go 语言圣经 8.4 Channels】代码仓库

    推荐阅读