Ala*_*way 1 error-handling channel go
我正在开发我的第一个真正的 Go 项目,一个消息传递 API。我使用通道在用户 goroutine 和使用线程不安全、基于事件的 C 协议库的库 goroutine 之间传递消息和其他数据。详情https://github.com/apache/qpid-proton/blob/master/proton-c/bindings/go/README.md
我的问题分为两个相关部分:
1. 处理跨渠道错误的常见习惯用法是什么?
一端的 goroutine 崩溃了,我如何确保另一端解除error阻塞,获得一个值并且以后不会再次阻塞?
对于读者:
struct { data, error } 优点缺点?其他想法?
对于作家:我不能不惊慌地关闭,所以我想我需要第二个渠道。这是惯用语吗?
select {
case sendChan <- data: sentOk()
case err := <- errChan: oops(err)
}
Run Code Online (Sandbox Code Playgroud)
关闭后我也无法写入,因此我需要将错误存储在某处并在尝试写入之前进行检查。还有其他方法吗?
2. 在 API 中公开渠道。
我需要通道来传递错误信息:我应该将这些通道设为公共字段还是将它们隐藏在方法中?
有一个权衡,我没有经验来评估它:
暴露通道让用户可以直接选择,但它需要他们正确执行错误处理模式(在写入之前检查错误,选择错误以及写入)。这看起来很复杂且容易出错,但也许是因为我不熟悉 Go。
在方法中隐藏通道可以简化并强制正确使用库。但是现在异步用户必须创建他们自己的 goroutine 和 channel(s)。他们可能只是复制图书馆已经做的事情,这很愚蠢。路径上还有一个额外的 goroutine 和 channel。也许这没什么大不了的,但数据通道是我的库的关键路径,我认为它必须与错误通道一起隐藏。
我可以做到这两点:为高级用户公开渠道,并为有简单需求的人提供简单的方法包装器。这更值得支持,但如果两者都不能适合所有情况,那就值得了。
标准 net.Conn 使用阻塞方法,而不是通道,我编写了 goroutines 将数据泵送到我的 C 事件循环通道,所以我知道它可以完成,但我没有发现它微不足道。net.Conn 正在包装系统调用而不是下面的通道,因此“公开通道”不是一个选项。是否有任何标准库导出带有错误处理的通道?(time.After不计算,没有错误)
非常感谢!艾伦
您的问题有点笼统,但我会尝试根据我编写高度并发代码的经验提供一些指导......
我个人认为使通道成为对象的属性,并以一种很好的有用NewMyObject() *MyObject方法进行初始化是一种很好的设计模式。它使得使用对象的代码不必在每次想要调用该类型提供的异步方法时进行样板设置。
For readers: I can close the channel, but no error info. I could pass a struct { data, error } or use a second channel. Pros & cons? Other ideas?
通过关闭中止通道让阅读器发出返回信号。temp, err := <-FromChannel如果数据或错误通道已关闭,读者应该简单地使用范式并继续执行。这应该可以防止工作人员出现“在关闭的频道上发送”恐慌错误,因为他们将关闭他们的频道并返回。当err != nil读者知道继续前进时。
For writers: I can't close without a panic so I guess I need a second channel. Is this idiomatic?
是的。可悲的是,我对通道的单向行为感到非常生气,尽管它应该被抽象化。无论如何,它不是。在我的代码中,我不会在异步工作的对象上定义它。我更喜欢的范例是使用关闭信号(因为在通道上发送 a 不是一对多的,只有一个 goroutine 会读取它)。相反,我在调用代码中分配了 abort 通道,如果需要关闭abort通道,则关闭通道,并且所有正在侦听该通道的执行异步工作的 goroutine 进行清理并返回。您还应该使用 WaitGroup 以便您可以在继续之前等待 goroutines 返回。
所以我的基本总结;
1) 让异步方法的调用者发出停止的信号,而不是相反。等候组更适合用于协调他们的退货
2)sync.WaitGroup在调用代码中使用 a来了解您的 goroutine 何时完成,以便您可以继续
3)在调用代码中分配你的错误通道,并利用关闭通道产生的一对多信号;如果您在调用者分配的通道上发送,则只有一个实例会从中读取。如果您在每个实例上放置一个,则必须迭代一组实例以在每个实例上发送。
4) 如果您的类型提供在后台工作的异步方法,请在其初始值设定项中设置要读取的通道,记录异步方法,说明在哪里侦听数据,提供非阻塞选择的示例将中止通道传递到异步方法并侦听方法数据和错误通道。如果您需要终止单个例程,则可以通过关闭它拥有的一个通道而不是通过关闭调用者abort通道来终止所有通道来实现此目的。
希望这一切都有意义。
| 归档时间: |
|
| 查看次数: |
2102 次 |
| 最近记录: |