ch1:=make(chan int,10)//创建传输int类型的双向通道,缓冲10个
readData:=<-ch1//读通道,读空通道会阻塞,通道关闭可以继续读
writerData:=1
ch1<-writerData //写通道,写满阻塞,通道关闭写会引发panic异常
readonlyCh:=make(<-chan int)//创建只读通道,不可写,不可关闭
writerOnlyCh:=make(chan<- int)//创建只写通道不可读,可关闭
select {
case data := <-onlyReadCh1:
fmt.Printf("data:%+v\n", data)
case data := <-onlyReadCh2:
fmt.Printf("data:%+v\n", data)
default:
fmt.Println("read nil data ")
}
select会阻塞,直到其中一个case被执行,当存在default时,其他case没有被执行条件就会进入default语句,那么select就没有阻塞的功能了。所以一般不会使用default。
select语句只会执行一次,所以想要循环读取,需要搭配for循环
for {
select {
case data := <-onlyReadCh1:
fmt.Printf("data:%+v\n", data)
case data := <-onlyReadCh2:
fmt.Printf("data:%+v\n", data)
}
}
因为有些场景时,接收方会等待数据一段时间,超过这段时间就认为发送方不会发送数据来了,那么就需要使用定时器来做一个定时。
for {
fmt.Println("in this ")
select {
case data := <-onlyReadChan:
fmt.Printf("data:%+v\n", data)
case <-time.After(3 * time.Second):
fmt.Println("out time ")
}
}
下面一个例子是,发送方和接收方约定1秒发送一次数据,超过3秒没有数据就认为双方断开连接了。关闭chan,然后断开连接。
type Data struct {
Name string
Index int
}
ch= make(chan Data, 100)
go handlerChan(ch)
for i := 0; i < 1000; i++ {
time.Sleep(1 * time.Second)
ch<- Data{
Name: "person_" + strconv.Itoa(i),
Index: i,
}
}
func handlerChan(onlyReadChan chan Data) {
FOR:
for {
fmt.Println("in this ")
select {
case data := <-onlyReadChan:
fmt.Printf("data:%+v\n", data)
case <-time.After(3 * time.Second):
fmt.Println("out time ")
break FOR
}
}
}
有2000个通道,每个人身上有他属于的那个通道的编号。
然后属于这2000个通道的人陆续的不断到来。
每个通道的人按照来的先后顺序被验票,不同通道的人没有先后顺序没有关系。
现在希望能够尽可能快的验票,但是保证相同通道的人按照先后顺序验票。
1.创建一个map保存通道,key是通道编号,value是100个缓存的chan。
2.来一个人先判断他对应的通道是否存在map中,不存在则创建对应的chan,
3.然后判断对应的chan是否正在检票(协程正在运行),没有则运行该协程读取chan,
4.最后将该人放在通道中进行检票(被协程读取处理)。
注释:协程里面对chan中的数据进行处理,并且放了个定时器,如果超过一个时间没有数据到来,那么就关闭通道并退出协程。来了新数据就按照2-3-4的顺序执行即可
package main
import (
"encoding/json"
"fmt"
"strconv"
"time"
)
type Data struct {
Name string
Index int
}
func handlerChan(onlyReadChan chan Data) {
FOR:
for {
fmt.Println("in this ")
select {
case data := <-onlyReadChan:
fmt.Printf("data:%+v\n", data)
case <-time.After(3 * time.Second):
fmt.Println("out time ")
close(onlyReadChan)
break FOR
}
}
}
func main() {
/*
数据分为不同类别,类别各自有自己的编号;不同类别的数据相互独立;相同类别的数据需要按照时间顺序处理
为每个类别创建一个有缓存的管道且起个单独的协程,该类数据超缓存阻塞写;数据读空了阻塞读且超过10分钟关闭该协程删除map中的k
创建一个map k是类别id v是chan;
*/
// 1 创建一万个协程为datachan(缓存100)写数据,写满阻塞
// 2 根据类别创建chan和协程,并且把类别id和chan写入全局map,map中k已存在且对于chan没关闭的直接写入k对于的chan;协程只处理对于chan的数据,超过10分钟读空则关闭该chan
var LocalMap = make(map[int](chan Data))
//这里模拟0-1000通道的人各来了100个
for j := 0; j < 100; j++ {
time.Sleep(1 * time.Second)
for i := 0; i < 1000; i++ {
if c, ok := LocalMap[i]; !ok {
LocalMap[i] = make(chan Data, 100)
go handlerChan(LocalMap[i])
} else {
if _, ok := <-c; !ok {
// 已经关闭,重新创建
LocalMap[i] = make(chan Data, 100)
go handlerChan(LocalMap[i])
}
}
LocalMap[i] <- Data{
Name: "wz_" + strconv.Itoa(i),
Index: i,
}
}
}
l1 := len(LocalMap)
time.Sleep(3 * time.Second)
//这里模拟1000-2000通道的人各来了100个
for j := 0; j < 100; j++ {
time.Sleep(1 * time.Second)
for i := 1000; i < 2000; i++ {
if c, ok := LocalMap[i]; !ok {
LocalMap[i] = make(chan Data, 100)
go handlerChan(LocalMap[i])
} else {
if _, ok := <-c; !ok {
// 已经关闭,重新创建
LocalMap[i] = make(chan Data, 100)
go handlerChan(LocalMap[i])
}
}
LocalMap[i] <- Data{
Name: "wz_" + strconv.Itoa(i),
Index: i,
}
}
}
l2 := len(LocalMap)
time.Sleep(3 * time.Second)
//这里模拟0-1000通道的人各来了100个
//此时0-1000的通道和协程已经关闭了,这里全都是新建的
for j := 0; j < 100; j++ {
for i := 0; i < 1000; i++ {
if c, ok := LocalMap[i]; !ok {
LocalMap[i] = make(chan Data, 100)
go handlerChan(LocalMap[i])
} else {
if _, ok := <-c; !ok {
// 已经关闭,重新创建
LocalMap[i] = make(chan Data, 100)
go handlerChan(LocalMap[i])
}
}
LocalMap[i] <- Data{
Name: "wz_" + strconv.Itoa(i),
Index: i,
}
}
}
fmt.Println("map1:", l1)
fmt.Println("map2:", l2)
fmt.Println("map3:", len(LocalMap))
time.Sleep(100 * time.Second)
}