赞
踩
var 变量名 chan 数据类型
在没有使用协程的情况下
,如果管道的数据已经全部取出,那么再取就会报错示例:
package main import( "fmt" ) func main(){ //定义管道 、 声明管道 ---> 定义一个int类型的管道 var intChan chan int //通过make初始化:管道可以存放3个int类型的数据 intChan = make(chan int,3) //证明管道是引用类型: fmt.Printf("intChan的值:%v",intChan) // 0xc000112080 //向管道存放数据: intChan<- 10 num := 20 intChan<- num intChan<- 40 //注意:不能存放大于容量的数据: //intChan<- 80 //在管道中读取数据: num1 := <-intChan num2 := <-intChan num3 := <-intChan fmt.Println(num1) fmt.Println(num2) fmt.Println(num3) //注意:在没有使用协程的情况下,如果管道的数据已经全部取出,那么再取就会报错: num4 := <-intChan fmt.Println(num4) //输出管道的长度: fmt.Printf("管道的实际长度:%v,管道的容量是:%v",len(intChan),cap(intChan)) }
使用内置函数close可以关闭管道,当管道关闭后,就不能再向管道写数据了,但是仍然可以从该管道读取数据
package main import( "fmt" ) func main(){ //定义管道 、 声明管道 var intChan chan int //通过make初始化:管道可以存放3个int类型的数据 intChan = make(chan int,3) //在管道中存放数据: intChan<- 10 intChan<- 20 //关闭管道: close(intChan) //再次写入数据:--->报错 //intChan<- 30 //当管道关闭后,读取数据是可以的: num := <- intChan fmt.Println(num) }
在遍历时,如果管道没有关闭,则报错:
package main import( "fmt" ) func main(){ //定义管道 、 声明管道 var intChan chan int //通过make初始化:管道可以存放100个int类型的数据 intChan = make(chan int,100) for i := 0;i < 100;i++ { intChan<- i } //在遍历前,如果没有关闭管道,就会出现deadlock的错误 //所以我们在遍历前要进行管道的关闭 close(intChan) //遍历:for-range for v := range intChan { fmt.Println("value = ",v) } }
package main import( "fmt" "time" "sync" ) var wg sync.WaitGroup //只定义无需赋值 //写: func writeData(intChan chan int){ defer wg.Done() for i := 1;i <= 50;i++{ intChan<- i fmt.Println("写入的数据为:",i) time.Sleep(time.Second) } //管道关闭: close(intChan) } //读: func readData(intChan chan int){ defer wg.Done() //遍历: for v := range intChan{ fmt.Println("读取的数据为:",v) time.Sleep(time.Second) } } func main(){//主线程 //写协程和读协程共同操作同一个管道-》定义管道: intChan := make(chan int,50) wg.Add(2) //开启读和写的协程: go writeData(intChan) go readData(intChan) //主线程一直在阻塞,什么时候wg减为0了,就停止 wg.Wait() }
运行:
在没有使用协程的情况下
,如果管道的数据已经全部取出,那么再取就会报错。所以上面即使写入后sleep两秒,读取也不会报错。
package main import( "fmt" ) func main(){ //默认情况下,管道是双向的--》可读可写: //var intChan1 chan int //声明为只写: var intChan2 chan<- int // 管道具备<- 只写性质 intChan2 = make(chan int,3) intChan2<- 20 //num := <-intChan2 报错 fmt.Println("intChan2:",intChan2) //声明为只读: var intChan3 <-chan int// 管道具备<- 只读性质 if intChan3 != nil { //非空 num1 := <-intChan3 fmt.Println("num1:",num1) } //intChan3<- 30 报错 }
管道只写入数据,不读取,超过容量:
package main import( "fmt" _"time" "sync" ) var wg sync.WaitGroup //只定义无需赋值 //写: func writeData(intChan chan int){ defer wg.Done() for i := 1;i <= 20;i++{ //超过容量管道的容量10 intChan<- i fmt.Println("写入的数据为:",i) //time.Sleep(time.Second) } //管道关闭: close(intChan) } func main(){//主线程 //定义管道: intChan := make(chan int,10) wg.Add(1) //开启写的协程: go writeData(intChan) wg.Wait() }
改一下,写的快,读的慢:没报错,但很明显,写被影响了,到最后被动等读协程,读走一个,写协程才能继续写。
select {
case <- channel1:
// 处理channel1的数据
case data := <- channel2:
// 处理channel2的数据
case channel3 <- value:
// 向channel3发送数据
default:
// 当没有任何通道准备就绪时执行default块
}
按顺序检查有没那个case后面的管道是可读或者可写的,有则执行该case语句。如果多个case同时满足,Go会随机选择一个执行。
如果没有任何case语句满足条件,且存在default语句,则执行default块中的代码。如果没有default语句,则select语句会被阻塞,直到至少有一个case语句满足条件。
package main import( "fmt" "time" ) func main(){ //定义一个int管道: intChan := make(chan int,1) go func(){ time.Sleep(time.Second * 5) intChan<- 10 }() //定义一个string管道: stringChan := make(chan string,1) go func(){ time.Sleep(time.Second * 2) stringChan<- "msbgolang" }() //fmt.Println(<-intChan)//本身取数据就是阻塞的 select{ case v := <-intChan : fmt.Println("intChan:",v) case v := <-stringChan : fmt.Println("stringChan:",v) default: fmt.Println("防止select被阻塞") } }
输出:
防止select被阻塞
上面两个case的协程都不能立即可读或可写,走了default。没有default,则输出:
msbgolang
因为其对应的管道阻塞时间短,2s后就可以读到了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。