channel
golang最显著的特性就是协程和通道了.
这块掌握好了 go语言就算是进阶了.
这里先把channel的各种情况,例子列出来,以便全面理解认识.
初步认识
使用make(chan val -type) 创建一个通道,通道类型就是传递值的类型.
channel <- 发送一个新的值到通道
<- channel 从通道接受一个值
package main
import "fmt"
func main() {
messages := make(chan string)
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
}
/*下面是打印出来的内容
ping
下面理解下通道缓存:
make(chan string,2) 后面的参数2表示该通道有2个缓存
上面例子的通道是没有缓存的 make(chan string)
也就是当一个协程将数据发送到通道,必需有人去接受.不然这个协程会一直阻塞这这里,不会进行下一步
package main
import (
"fmt"
"time"
)
func main() {
messages := make(chan string)
go func() {
fmt.Println("我:发送完成")
messages <- "通道数据"
fmt.Println("我:可以继续工作了")
}()
time.Sleep(time.Second*5)
fmt.Println("时间过去了5秒")
msg:= <-messages
fmt.Println("收到",msg)
time.Sleep(time.Second*2)
}
/*
该例子运行后很直观
我:发送完成
时间过去了5秒
收到 通道数据
我:可以继续工作了
上面例子如果改成 messages := make(chan string,2) 后面增加了缓存
/*
我:发送完成
我:可以继续工作了
时间过去了5秒
收到 通道数据
那么协程发送完数据就去忙自己的了
阻塞和非阻塞 在后面写项目时可以灵活运用
如阻塞可用于同步协程的执行状态
package main
import "fmt"
import "time"
// 这是一个我们将要在 Go 协程中运行的函数。`done` 通道
// 将被用于通知其他 Go 协程这个函数已经工作完毕。
func worker(done chan bool) {
fmt.Print("我在工作...")
time.Sleep(time.Second)
fmt.Println("工作完了")
// 发送一个值来通知我们已经完工啦。
done <- true
}
func main() {
// 运行一个 worker Go协程,并给予用于通知的通道。
done := make(chan bool, 1)
go worker(done)
// 程序将在接收到通道中 worker 发出的通知前一直阻塞。
<-done
}
/*结果为
我在工作...工作完了
如果把 <- done 这行代码从程序中移除,程序甚至会在 worker还没开始运行时就结束了
通道方向:当通道作为一个函数的参数的时候我们可以指定这个通道智能发送或者接受.这个特性提升了安全性
package main
import "fmt"
// `ping` 函数定义了一个只允许发送数据的通道。尝试使用这个通
// 道来接收数据将会得到一个编译时错误。
func ping(pings chan<- string, msg string) {
pings <- msg
}
// `pong` 函数允许通道(`pings`)来接收数据,另一通道
// (`pongs`)来发送数据。
func pong(pings <-chan string, pongs chan<- string) {
msg := <-pings
pongs <- msg
}
func main() {
pings := make(chan string, 1)
pongs := make(chan string, 1)
ping(pings, "passed message")
pong(pings, pongs)
fmt.Println(<-pongs)
}
chan<- 只能接受
<-chan 只能发送