惯用的 Golang 协程

在 Go 中,如果我们有一个类型的方法启动一些循环机制(轮询 A 并永远执行 B),最好将其表示为:


// Run does stuff, you probably want to run this as a goroutine

func (t Type) Run() {

    // Do long-running stuff

}

并记录这可能希望作为 goroutine 启动(并让调用者处理它)


或者向调用者隐藏它:


// Run does stuff concurrently

func (t Type) Run() {

   go DoRunStuff()

}

我是 Go 的新手,不确定约定是否让调用者前缀为“go”,或者在代码设计为异步运行时为他们做这件事。


我目前的观点是我们应该记录并给调用者一个选择。我的想法是,在 Go 中,并发实际上并不是公开接口的一部分,而是使用它的一个属性。这是正确的吗?


慕田峪7331174
浏览 197回答 3
3回答

莫回无

在我开始为我想要并发的 Web 服务编写适配器之前,我对此有您的看法。我有一个必须启动的 go 例程来解析从 web 调用返回到通道的结果。如果不将其用作 go 例程,则绝对不会出现此 API 可以工作的情况。然后我开始查看像 net/http 这样的包。该包中有强制并发。在接口级别记录它应该能够同时使用,但是默认实现会自动使用 go 例程。因为 Go 的标准库通常在它自己的包中触发 go 例程,我认为如果你的包或 API 有保证,你可以自己处理它们。

侃侃尔雅

我目前的观点是我们应该记录并给调用者一个选择。我倾向于同意你的看法。由于 Go 使并发运行代码变得如此容易,因此您应该尽量避免 API 中的并发(这会迫使客户端并发使用它)。相反,创建一个同步 API,然后客户端可以选择同步或并发运行它。特别是幻灯片 26,显示的代码更像您的第一个示例。我会将该net/http包视为一个例外,因为在这种情况下,并发几乎是强制性的。如果包没有在内部使用并发,客户端代码几乎肯定必须使用。例如,http.Client(据我所知)不会启动任何 goroutine。只有服务器这样做。在大多数情况下,无论哪种方式,它都将是调用者的一行代码:go Run() 或者 StartGoroutine()同步 API 并不难同时使用,并为调用者提供更多选择。

扬帆大鱼

没有“正确”的答案,因为情况不同。显然,在某些情况下,API 可能包含实用程序、简单算法、数据集合等,如果打包为 goroutines 会看起来很奇怪。相反,在某些情况下,自然会期望“幕后”并发,例如丰富的 IO 库(http 服务器就是一个明显的例子)。对于更极端的情况,请考虑您要生成即插即用并发服务库。这样的 API 由模块组成,每个模块都通过通道具有详细描述的接口。显然,在这种情况下,它不可避免地会涉及作为 API 一部分的 goroutine。一个线索很可能是函数参数中是否存在通道。但我希望清楚地记录两种方式的预期结果。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go