为了账号安全,请及时绑定邮箱和手机立即绑定

在收听和服务时使用缓冲通道处理错误

在收听和服务时使用缓冲通道处理错误

Go
萧十郎 2022-04-26 14:53:49
我正在阅读有关使用go.作者没有直接使用http.ListenAndServe()方法,而是创建了http.Server结构。然后他继续:创建用于侦听错误的缓冲通道serverErrors := make(chan errors, 1)生成绑定到该通道的 http 监听 goroutinego func(){    fmt.Println("starting...")    serverErrors <- api.ListenAndServe()}()使用缓冲通道的原因是根据讲师的说法这样如果我们不收集这个错误,goroutine 就可以退出在程序下面确实有一个select块,正在收集来自该通道的错误。如果我们不收集错误,任何人都可以帮助我了解 goroutine 如何退出?如果我们使用无缓冲通道,实际的区别是什么?
查看完整描述

2 回答

?
慕斯王

TA贡献1864条经验 获得超2个赞

简短的回答:

对于任何通道(缓冲或不缓冲),如果没有任何内容写入通道,则通道读取块。

对于非缓冲通道,如果没有人在听,通道写入将阻塞。

这是错误通道的常用技术(因为只有一个项目会写入通道),使其成为大小为 1 的缓冲通道。它确保写入不会阻塞 - 并且 writer goroutine 可以继续其方式和返回。

因此,服务不依赖从错误通道读取的客户端调用者来执行其清理。

注意:要回收一个通道重新 GC,它只需要超出范围 - 它不需要完全耗尽。也不需要关闭。一旦它从两端超出范围,它将被 GC'ed。



查看完整回答
反对 回复 2022-04-26
?
catspeake

TA贡献1111条经验 获得超0个赞

如果您参考 的代码ListenAndServe(),您会注意到以下关于其工作原理的注释。从那里引用本身:


// ListenAndServe 总是返回一个非零错误。在 Shutdown 或 Close 之后,

// 返回的错误是 ErrServerClosed。


还,


// 当调用 Shutdown 时,Serve、ListenAndServe 和

// ListenAndServeTLS 立即返回 ErrServerClosed。确保

// 程序没有退出,而是等待 Shutdown 返回。


Shutdown考虑到您正在优雅地处理服务器的关闭并且不让 goroutine 在优雅关闭之前退出,您的 select 块正在等待(错误)。


在func (srv *Server) Close() (例如,大多数使用defer srv.Close(),对吗?)的情况下:


// Close 立即关闭所有活动的 net.Listener 和任何

// 处于 StateNew、StateActive 或 StateIdle 状态的连接。为一个


// 关闭返回关闭服务器的

// 底层监听器返回的任何错误。

// 优雅关机,使用 Shutdown。


因此,与上述相同的解释是使用 select 块。


现在,让我们将通道分类为buffered和unbuffered,如果我们确实关心信号传递的保证(与通道的通信),那么无缓冲的可以确保它。然而,如果在您的情况下缓冲通道(大小 = 1),那么它可以确保交付但可能会延迟。


让我们详细说明unbuffered channels:


A send operation on an unbuffered channel blocks the sending goroutine until another 

goroutine executes a corresponding receive on that same channel, at which point the value 

is transmitted and both goroutines may continue


Conversely, if received on the channel earlier (<-chan) than send operation, then the 

receiving goroutine is blocked until the corresponding send operation occurs on the 

same channel on another goroutine.

上述无缓冲通道的点表示同步性质。


记住,func main()也是一个goroutine。


让我们详细说明buffered channels:


A send operation on a buffered channel pushes an element at the back of the queue, 

and a receive operation pops an element from the front of the queue. 

 1. If the channel is full, the send operation blocks its goroutine until space is made available by another goroutine's receive. 

 2. If the channel is empty, a receive operation blocks until a value is sent by another goroutine.

因此,在您的情况下,通道的大小为 1。另一个发送者 goroutine 可以以非阻塞方式发送,因为另一个 goroutine 的接收者通道在收到后立即将其出列。但是,如果你还记得,我提到了大小为 1的通道的延迟交付,因为我们不知道接收器通道 goroutine 返回需要多少时间。


因此,使用阻塞发送者 goroutine select block。从引用代码的文档中,您可以看到


// 确保程序不会退出,而是等待 Shutdown 返回。


另外,为了更清楚,您可以参考:通道 的行为作者非常清楚地解释了它。


查看完整回答
反对 回复 2022-04-26
  • 2 回答
  • 0 关注
  • 106 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信