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语言基础
代码仓库