我觉得我的问题的答案是肯定的,但要求确定,因为我只是开始玩Go几天。我们是否应该将IO绑定任务(如http请求)封装到goroutine中,即使它是用于顺序用例的?
这是我天真的例子。假设我有一个方法可以生成3个http请求但需要按顺序执行。创建invoke
方法作为goroutines有什么好处吗?我理解下面的例子实际上会受到性能影响。
func myMethod() {
chan1 := make(chan int)
chan2 := make(chan int)
chan3 := make(chan int)
go invoke1(chan1)
res1 := <-chan1
invoke2(res1, chan2)
res2 := <-chan2
invoke3(res2, chan3)
// Do something with <-chan3
}
我想到的一个可能的原因是,未来证明invoke
方法,以便在其他开发重新使用该方法后在并发上下文中调用它们时。还有其他原因吗?
答案 0 :(得分:5)
没有任何标准可以对这个问题说是或否。
虽然你可以通过这种方式正确地做到这一点,但坚持顺序执行要简单得多。
有三个理由浮现在脑海中:
result, err := invoke; if err != nil ....
而不是通过渠道传递结果和错误就会简单得多invoke
方法,请在将来更改您的代码。在函数周围添加异步包装器就好了。答案 1 :(得分:1)
我参加派对有点晚了,但我想我还有一些事情要分享。
在回答这个问题之前,我想稍微深入一下Go Proverb,并发不是parellism 。对于goroutine和Go的语言特征,这是一个非常普遍的误解,当人们想到goroutine时,他们会考虑被剥夺的能力。
但正如Rob Pike在许多围棋谈判中所指出的那样,Go和goroutine实际上提供的是真实的。 Concurency是一个更好地融合现实世界,代码方式和结构,代码交互方式的模型。
回到这个问题。步骤顺序时应该使用goroutine吗?这取决于设计。如果你的代码由非常自然地相互通信的各个部分组成,或者你的某些代码保留了一个状态,并且经常return
只是没有意义,或者如果你的代码适合任何其他的可靠性设计,它就是完全可以使用goroutine和channel以及select
语句。 Rob Pike再次给出了现在Go text/template
使用的词法分析器的Go Talk,其中词法分析器使用goroutine,但解析器显然只是顺序使用词法分析器。他表示,通过使用goroutine和channel,只需要一点点性能,就可以实现更好的API。
但另一方面,在你的例子中,可能你正在考虑的事情(代码可能需要未来的parellism),我同意@Marc。坚持阻止通话,至少目前是这样。
答案 2 :(得分:0)
您可以使用像buf这样的频道,或者使用[]字符串(字符串网址片段)。如果你只需要顺序执行,你就不会从gorutines中获得任何好处,因为我们无法控制goroutine。
但我们可以要求不要等runtime.Gosched()
来自文档: Gosched产生处理器,允许其他goroutines运行。它不会挂起当前的goroutine,因此执行会自动恢复。
顺序执行的示例:
package main
func main() {
urls := []string{
"https://google.com",
"https://yahoo.com",
"https://youtube.com",
}
buf := make([][]byte, 0, len(urls))
for _, v := range urls {
buf = append(buf, sendRequest(v))
}
}
func sendRequest(url string) []byte {
//send
return []byte("")
}
答案 3 :(得分:-1)
对于这样的解决方案,我认为你在现实世界中解决问题没有任何好处。这并不意味着您的解决方案无法获益。如果您在练习后例如同步去例行程序,那么您将有大量的可能性进行实验和学习。
所以对我而言,这远不是一个明确的否定,但也不清楚是的。我不会说可能,这取决于你究竟是什么。您是在真正解决问题还是学习之后?