Go语言中channel的使用

channel创建

双向通道

ch1:=make(chan int,10)//创建传输int类型的双向通道,缓冲10个
readData:=<-ch1//读通道,读空通道会阻塞,通道关闭可以继续读
writerData:=1
ch1<-writerData //写通道,写满阻塞,通道关闭写会引发panic异常

单向通道

readonlyCh:=make(<-chan int)//创建只读通道,不可写,不可关闭
writerOnlyCh:=make(chan<- int)//创建只写通道不可读,可关闭

使用select读取通道

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)
	}
}

使用time定时器来让阻塞定时

因为有些场景时,接收方会等待数据一段时间,超过这段时间就认为发送方不会发送数据来了,那么就需要使用定时器来做一个定时。

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)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值