何时应考虑使用终结器来关闭通道?
来源:stackoverflow
时间:2024-03-20 23:18:44 338浏览 收藏
在 Go 泛型提案中,“何时应考虑使用终结器来关闭通道?”是一个常见问题。Ranger 函数通过使用终结器来解决接收方需要/可能停止通信的非一般情况。传统的通道无法让接收方向发送方发出信号,表明接收方已失去兴趣。Ranger 函数通过使用额外的通道和终结器来实现此功能,当接收方停止接收时,终结器将关闭该通道,向发送方发出信号。
这是两个问题中的第二个问题(这是第一个问题),旨在帮助理解 go 泛型提案示例。
特别是,到目前为止,我在理解标题为“通道”的提案示例部分中的两段代码时遇到了麻烦:
我遇到的第二个问题是 ranger
函数的以下定义。
也就是说,我不明白需要调用 runtime.setfinalizer(r,r.finalize)
实际上 *receiver[t]
类型的 finalize
) 方法应该做的只是表示接收器已完成接收值的信号 (close(r.done)
)。
在我看来,通过为 *receiver[t]
提供终结器,代码将关闭接收器的义务委托给运行时。
我理解这段代码的方式是,当 gc 决定前者是时, *receiver[t]
向 *sender[t]
发出信号,它将不再接收任何值。无法访问,即没有更多可用的引用。
如果我的解释是正确的,为什么要等那么久接收方才发出信号已完成?难道不能以某种方式在代码中显式处理 close
操作吗?
代码:
// Ranger provides a convenient way to exit a goroutine sending values // when the receiver stops reading them. // // Ranger returns a Sender and a Receiver. The Receiver provides a // Next method to retrieve values. The Sender provides a Send method // to send values and a Close method to stop sending values. The Next // method indicates when the Sender has been closed, and the Send // method indicates when the Receiver has been freed. func Ranger[T any]() (*Sender[T], *Receiver[T]) { c := make(chan T) d := make(chan bool) s := &Sender[T]{values: c, done: d} r := &Receiver[T]{values: c, done: d} // The finalizer on the receiver will tell the sender // if the receiver stops listening. runtime.SetFinalizer(r, r.finalize) return s, r } // A Sender is used to send values to a Receiver. type Sender[T any] struct { values chan<- T done <-chan bool } // Send sends a value to the receiver. It reports whether any more // values may be sent; if it returns false the value was not sent. func (s *Sender[T]) Send(v T) bool { select { case s.values <- v: return true case <-s.done: // The receiver has stopped listening. return false } } // Close tells the receiver that no more values will arrive. // After Close is called, the Sender may no longer be used. func (s *Sender[T]) Close() { close(s.values) } // A Receiver receives values from a Sender. type Receiver[T any] struct { values <-chan T done chan<- bool } // Next returns the next value from the channel. The bool result // reports whether the value is valid. If the value is not valid, the // Sender has been closed and no more values will be received. func (r *Receiver[T]) Next() (T, bool) { v, ok := <-r.values return v, ok } // finalize is a finalizer for the receiver. // It tells the sender that the receiver has stopped listening. func (r *Receiver[T]) finalize() { close(r.done) }
正确答案
TLDR:您的理解是正确的,done
通道可能只是由接收方“手动”关闭,以表示失去兴趣(停止通信并解除发送方的职责)。
通道用于让 goroutine 以并发安全的方式进行通信。惯用的用法是发送方不断发送值,一旦没有更多的值可发送,发送方就会发出关闭通道的信号。
接收方不断从通道接收数据,直到通道关闭,这表明通道上不会(不能)再有任何值。这通常/最容易通过通道使用 for range
来完成。
所以通常接收方必须继续接收直到通道关闭,否则发送方将永远被阻止。通常这是可以/足够的。
演示的 Ranger()
构造适用于接收方需要/可能停止通信的非一般情况。
单个通道无法让接收方向发送方发出信号,表明接收方已失去兴趣,并且不需要更多值。这需要一个额外的通道,接收者必须关闭该通道(当然发送者也必须监视)。只要有一个接收器,这也可以。但如果有多个接收者,关闭 done
通道会变得有点复杂:所有接收者都不能关闭 done
通道:关闭已经关闭的通道会出现恐慌。因此接收方也必须进行协调,因此只有一个接收方,或者更确切地说,协调方本身关闭 done
通道,仅一次;这必须在所有接收者“放弃”频道之后发生。
Ranger()
通过使用终结器委托关闭 done
通道来帮助解决此问题。这是可以接受的,因为通常停止通信甚至不是接收者的任务,但在极少数情况下,如果这种情况仍然出现,它将被处理(以一种简单的方式,不需要额外的,协调器 goroutine)。
以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
139 收藏
-
204 收藏
-
325 收藏
-
477 收藏
-
486 收藏
-
439 收藏
-
357 收藏
-
352 收藏
-
101 收藏
-
440 收藏
-
212 收藏
-
143 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习