惯用Golang goroutines

时间:2015-02-13 18:12:54

标签: go

在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中,并发性实际上并不是暴露接口的一部分,而是使用它的属性。这是对的吗?

3 个答案:

答案 0 :(得分:10)

我对此有了自己的看法,直到我开始为一个我希望并发的Web服务编写适配器。我有一个go例程,必须启动它来解析从Web调用返回到通道的结果。绝对没有这种API可以在不将其用作go例程的情况下工作的情况。

然后我开始查看net / http这样的软件包。该包中存在强制并发。在接口级别记录它应该能够同时使用,但默认实现自动使用go例程。

因为Go的标准库通常会在其自己的包中触发go例程,所以我认为如果您的包或API保证它,您可以自己处理它们。

答案 1 :(得分:9)

  

我目前的观点是,我们应该记录并给予呼叫者一个选择。

我倾向于同意你的观点。

由于Go使得同时运行代码变得如此容易,因此您应该尽量避免API中的并发(这会迫使客户端同时使用它)。相反,创建一个同步API,然后客户端可以选择同步或同时运行它。

几年前的一次演讲中讨论过这个问题:Twelve Go Best Practices

特别是幻灯片26显示的代码更像您的第一个示例。

我会将net/http包视为异常,因为在这种情况下,并发性几乎是强制性的。如果包在内部不使用并发,那么客户端代码几乎肯定必须。例如,http.Client没有(据我所知)启动任何goroutines。只有服务器这样做。

在大多数情况下,无论如何,它都将成为调用者代码的一行:

go Run()StartGoroutine()

同步API并不难同时使用,并为调用者提供了更多选项。

答案 2 :(得分:1)

没有'权利'答案因为情况不同。

显然,在某些情况下,API可能包含实用程序,简单算法,数据集合等,如果打包为goroutines则会显得很奇怪。

相反,在某些情况下,人们很自然地期待“引擎盖下”。并发性,例如丰富的IO库(http服务器就是一个明显的例子)。

对于更极端的情况,请考虑您要生成一个即插即用并发服务库。这样的API由模块组成,每个模块通过通道具有良好描述的接口。显然,在这种情况下,它将不可避免地涉及从API开始的goroutines。

一个线索可能是函数参数中是否存在通道。但我希望能够清楚地记录出任何一种方式。