通道是什么,通道就是goroutine之间的通道。它可以让goroutine之间相互通信。通道通过语句:ch := make(chan int) 来进行创建,是int类型也可以是其它类型。通道数据的发送和接收通过<-来进行。
func main() {
ch := make(chan int) //创建一个通道
go func() {
ch <- 1 //给通道发送值
}()
x := <-ch //从通道中取值
fmt.Println(x) //1
}
注意一点:通道是goroutine之间的连接,所以通道的发送和接收必须处在不同的goroutine中。
上面的代码中,通道中只能发送一个值,这种通道称为无缓冲通道,那么与之对应的就是有缓冲通道,它的创建语句如下:
ch := make(chan int, 3) //创建了一个容量为3的通道
在上一篇博客中,在主goroutine中创建三个goroutine方法,当主goroutine方法结束时,所有的goroutine都结束,那么现在有了通道,我们可以将之前的代码修改一下,不用主goroutine沉睡来实现当所有的goroutine结束时,主goroutine结束,代码如下:
// demo project main.go
package main
import (
"fmt"
)
func testGoroutine(ch chan struct{}) {
fmt.Println("Hello World")
ch <- struct{}{} //往通道中发送值
}
func main() {
ch := make(chan struct{})
go testGoroutine(ch)
<-ch //从通道中取值,如果通道为空,等待,直到通道中取到值
}
通道提供了单向通道,单向通道分为发送通道和接收通道,发送通道只能发送数据,接收通道只能用来接收数据,看以下代码:
// demo project main.go
package main
import (
"fmt"
)
//单向发送通道
func SendMsg(sendMsg chan<- string) {
sendMsg <- "hello world"
}
/**
*@sendMsg 单向发送通道
*@getMsg 单向接收通道
*
**/
func GetMsg(sendMsg chan<- string, getMsg <-chan string) {
sendMsg <- (<-getMsg)
}
func main() {
outMsg := make(chan string)
inMsg := make(chan string)
go SendMsg(outMsg)
go GetMsg(inMsg, outMsg)
fmt.Println(<-inMsg)
}
上面这个事例可能不太好,但是就是这个意思。
缓冲通道有一个元素队列,队列的最大长度在创建通道时通过make的容量参数来设置ch := make(chan int, 3),创建了一个可以容纳三个整数的通道。下面通过一段代码来看下:
// demo project main.go
package main
import (
"fmt"
)
func testGoroutine(ch chan string, param string) {
fmt.Println("Hello World")
ch <- param
}
func main() {
ch := make(chan string, 3) //创建一个通道
go testGoroutine(ch, "A")
go testGoroutine(ch, "B")
go testGoroutine(ch, "C")
for i := 0; i < cap(ch); i++ {
fmt.Println(<-ch)
}
}
select多路复用
select和switch很相似,select时作用在通道上的语句。让我们来假设一种场景,机器做某一个操作,条件是有信号时才可以执行此操作,没有信号时等待信号,做100次停止,下面用一段代码来模拟:
// demo project main.go
package main
import (
"fmt"
)
func main() {
opCh := make(chan int, 1)
for i := 0; i < 100; i++ {
select {
case <-opCh:
fmt.Println("do it")
case opCh <- i:
//do nothing
}
}
}
这篇就到这里,下一篇做一些练习,巩固下前面所学的知识点