Go之路(二十五):Channel
Channel
协程之间的通信有两种方式
1.全局变量和锁
2.channel
上个章节中用到的就是全局变量和锁的方式来操作一个公共数据
channel的概念

channel已经实现了线程安全,不需要额外加锁了
channel的基本用法:
package main
import(
"fmt"
)
type Student struct{
Name string
Age int
}
func main() {
var intChan chan interface{}
intChan = make(chan interface{}, 10)
stu1 := Student{
Name:"tom",
Age: 13,
}
intChan <- stu1
stu2 := <- intChan
var stu3 interface{}
stu3, ok := stu2.(Student)
if !ok{
fmt.Println("NO")
}
fmt.Println(stu3)
}
虽然channel需要指明类型,但是如果指定为空接口的话就可以传输任意类型的数据了
另外可以用断言来转换数据
例子2:判断一万以内的质数
package main
import(
"fmt"
"time"
)
func cal(a chan int, result chan int){
for v := range a{
flag := true
for i:=2;i<v;i++{
if v%i==0{
flag = false
break
}
}
if flag{
result <- v
}
}
}
func main() {
var task = make(chan int,100)
var result = make(chan int,100)
go func (){
for i:=0;i<10000;i++{
task <- i
}
close(task)
}()
for i:=0;i<4;i++{
go cal(task,result)
}
go func(){
for v:= range result{
fmt.Println(v)
}
}()
time.Sleep(time.Second*5)
}
1.管道可以关闭,关闭后不能继续放值
2.可以用for range语句来取管道内的值
3.可以用ok来判断管道是否关闭
v,ok := <-task
if ok == false{
fmt.Println("管道已经关闭")
}
如果for{}不加条件,然后里面是
v,ok := <-task,就会出现下面的情况
不关闭管道一直取值取到空的时候是会阻塞的,但是一旦关闭管道,取完值后再继续取值就会一直取到0(空值)
但是如果是for range 取完就自动退出了
可以再用一个管道来确认目标协程是否执行完
例子:
package main
import(
"fmt"
"math/rand"
)
func cal(a chan int, result chan int,exist chan int){
for v := range a{
flag := true
for i:=2;i<v;i++{
if v%i==0{
flag = false
break
}
}
if flag{
result <- v
}
}
fmt.Println("exit")
exist <- rand.Intn(10)
}
func main() {
var task = make(chan int,100)
var result = make(chan int,100)
var exist = make(chan int,4)
go func (){
for i:=0;i<10000;i++{
task <- i
}
close(task)
}()
for i:=0;i<4;i++{
go cal(task,result,exist)
}
go func (){for i:=0;i<4;i++{
b := <- exist
fmt.Println(b)
}
close(result)
}()
for _= range result{
// fmt.Println(v)
}
}
但是要注意这个确认的需要另外起一个协程,因为go的自检测机制会认为这个是死锁
非阻塞以及多路复用可以用select
select是Go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。
select随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。一个默认的子句应该总是可运行的。
例子:
package main
import(
"fmt"
"time"
)
func main() {
var a = make(chan int,5)
var b = make(chan int,5)
go func(){
var i int
for {
a <- i
time.Sleep(time.Second)
b <- i*i
time.Sleep(time.Second)
i++
}
}()
for{
select{
case v := <- a:
fmt.Println(v)
case v:= <- b:
fmt.Println(v)
default:
time.Sleep(time.Second)
fmt.Println("?")
}
}
}
只读 <-chan 只写chan<-

浙公网安备 33010602011771号