go的一些实现(关于channel循环打印,限流等等)

go如何实现深拷贝?

  • 序列化和反序列化
import (
	"bytes"
	"encoding/gob"
	"fmt"
)


func deepCopy(dst, src interface{}) error {
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(src); err != nil {
		return err
	}
	return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst)
}

两个协程交替打印奇偶数

2025.3.7 更新更完善的写法

//两个协程交替打印奇偶数

func main() {
	flagChan := make(chan struct{})
	done := make(chan struct{})

	go func() {
		defer close(done) //最终奇数先结束
		for i := 1; i <= 10; i += 2 {
			fmt.Println("奇数", i)
			flagChan <- struct{}{} //写入唤醒偶数携程
			<-flagChan             //等待偶数协程唤醒
		}
	}()

	//偶数协程
	go func() {
		for i := 2; i <= 10; i += 2 {
			<-flagChan //先读chan,保证后执行
			fmt.Println("偶数", i)
			flagChan <- struct{}{}
		}
	}()

	<-done // 奇数结束关闭,然后读取默认值结束,否则阻塞
}

两个协程循环打印字母和数字

//两个协程轮流打印数字和字母  A 1 B 2 C 3 .... Z 26


func main(){
	Buffer() //有缓冲的方式
	NoBuffer() //无缓冲的方式
}


//有缓冲区的chan循环打印.

func Buffer(){
	strChan:=make(chan struct{},1)
	numChan:=make(chan struct{},1)

	//先向numChan中放入作为开启
	numChan<- struct{}{}

	go func(){
		for i:='A';i<='Z';i++{
			<-numChan //读取之后才能继续
			fmt.Printf("%v ",string(i))
			strChan<- struct{}{}
		}
	}()

	go func() {
		for i:=1;i<=26;i++{
			<-strChan
			fmt.Printf("%v ",i)
			numChan<- struct{}{} //通知数字打印完毕
		}
	}()

	time.Sleep(3*time.Second)
}



//无缓冲的chan实现方式
func NoBuffer(){
	//
	strChan:=make(chan struct{})
	numChan:=make(chan struct{})

	go func(){
		for i:='A';i<='Z';i++{
			fmt.Printf("%v ",string(i))
			strChan<- struct{}{}
			<-numChan //读取之后才能继续
		}
	}()

	go func() {
		for i:=1;i<=26;i++{
			<-strChan
			fmt.Printf("%v ",i)
			numChan<- struct{}{} //通知数字打印完毕
		}
	}()

	time.Sleep(3*time.Second)
}

N个协程循环打印1-100

//N个协程交替打印1-100
const NUM = 5  //假设5个协程交替打印

func main(){

	exitChan:=make(chan int,1) //退出的标识
	chanNums:=make([]chan int,0)  //chan数组 ,开启多个协程哪个对应的chan到达则可以运行
	res:=1 //全局res,因为交替打印,多协程操作也不需要加锁
	index:=0 //协程标识,到达NUM重新归零

	for i:=0;i<NUM;i++{  //初始化对应的chan
		chanNums = append(chanNums,make(chan int,1))
	}


	for i:=0;i<NUM;i++{
		go func(i int) { //开启NUM个协程
			for { //循环打印
				<-chanNums[i] //对应的chan存在数据才打印
				if res>100{ //越界退出
					exitChan<-1
					break
				}
				fmt.Println("goroutine",i, "res:",res)
				res++

				index = (index+1)%NUM  //5个协程index为0,1,2,3,4  到达4之后重新归零

				chanNums[index]<-1 //放入下一个
			}
		}(i)
	}

	//初始化时候先把第一个打印goroutine开启
	chanNums[0]<-1

	//退出标识存在才会退出
	select {
	case <-exitChan:
		fmt.Println("main终止")
	}
}

posted @ 2022-06-11 23:00  海拉尔  阅读(377)  评论(0)    收藏  举报