您的当前位置:首页正文

Golang优雅关闭channel【生产者-消费者-第三方】

2024-11-26 来源:个人技术集锦

起因:当前我们代码遇到困境 最后会报错

简答说 你在一个关闭的通道发消息

那么你发送之前 检查一下 如果已经关闭了 就不发了 【治标不治本 先试一试】 

Golang优雅关闭channel的方法示例-所谓就优雅就是不要暴力的关闭 而是发下一个关闭的消息 让发消息的协程自己去关闭

奇怪的是WIN10跑他的代码 没有问题!!树莓派run的话 一会就嗝屁!!!

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	jobs := make(chan int)
	var wg sync.WaitGroup

	go func() {
		time.Sleep(time.Second * 3)
		close(jobs)
	}()

	go func() {
		for i := 0; ; i++ {
			jobs <- i
			fmt.Println("produce:", i)
		}
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := range jobs {
			fmt.Println("consume:", i)
		}
	}()
	wg.Wait()
}

它修改后的代码

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	jobs := make(chan int)
	timeout := make(chan bool)
	var wg sync.WaitGroup
	go func() {
		time.Sleep(time.Second * 3)
		timeout <- true
	}()
	go func() {
		for i := 0; ; i++ {
			select {
			case <-timeout:
				close(jobs)
				return

			default:
				jobs <- i
				fmt.Println("produce:", i)
			}
		}
	}()
	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := range jobs {
			fmt.Println("consume:", i)
		}
	}()
	wg.Wait()
}

Go sync.WaitGroup的用法

主线程为了等待goroutine都运行完毕,

不得不在程序的末尾使用time.Sleep() 来睡眠一段时间,等待其他线程充分运行。

对于简单的代码,100个for循环可以在1秒之内运行完毕,time.Sleep() 也可以达到想要的效果。

但是对于实际生活的大多数场景来说,1秒是不够的,

并且大部分时候我们都无法预知for循环内代码运行时间的长短。

这时候就不能使用time.Sleep() 来完成等待操作了。

管道在这里显得有些大材小用,因为它被设计出来不仅仅只是在这里用作简单的同步处理,在这里使用管道实际上是不合适的。而且假设我们有一万、十万甚至更多的for循环,也要申请同样数量大小的管道出来,对内存也是不小的开销。

对于这种情况,go语言中有一个其他的工具sync.WaitGroup 能更加方便的帮助我们达到这个目的。

WaitGroup 对象内部有一个计数器,最初从0开始,它有三个方法:Add(), Done(), Wait() 用来控制计数器的数量。

Add(n) 把计数器设置为n ,

Done() 每次把计数器-1 ,

wait() 会阻塞代码的运行,直到计数器地值减为0

继续看前面的文章

1----

	go func() {
		time.Sleep(time.Millisecond * 1)
		close(jobs)
	}()

 修改为这样 更快出现问题 概率死机

而 如果 不要上面这个关闭函数 

永远不会死机

2---用途

3---解决文章开头我们的问题

也就是自己关闭 外部发消息过来 生产者关闭 

显示全文