步骤连续时使用goroutine

步骤连续时使用goroutine,go,goroutine,Go,Goroutine,我觉得我的问题的答案是否定的,只是要求确定,因为我才开始玩围棋几天。我们是否应该将IO绑定的任务(如http请求)封装到goroutine中,即使它将在顺序用例中使用 这是我天真的例子。假设我有一个方法,可以发出3个http请求,但需要按顺序执行。将invoke方法创建为goroutines有什么好处吗?我知道下面的例子实际上会影响性能 func myMethod() { chan1 := make(chan int) chan2 := make(chan int) chan3

我觉得我的问题的答案是否定的,只是要求确定,因为我才开始玩围棋几天。我们是否应该将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
}
func myMethod(){
通道1:=制造(通道内部)
通道2:=制造(通道内部)
通道3:=制造(通道内部)
go invoke1(通道1)

res1:=没有任何标准会对这个问题说是或不是

虽然您可以通过这种方式正确地执行,但坚持简单的顺序执行要简单得多

我想到三个原因:

  • 这仍然是顺序的:您正在按顺序等待每一个goroutine,因此这不会给您带来任何好处。如果只是执行一个http请求,性能可能不会有太大变化,这两种情况都将花费大部分时间等待响应
  • 如果只获得
    结果,err:=invoke;if err!=nil….
    则错误处理要简单得多,而不必通过通道传递结果和错误
  • 过度泛化是一个比“未来验证”更合适的词。如果将来需要异步调用
    invoke
    方法,那么以后可以更改代码。在函数周围添加异步包装也同样容易

您可以使用像buf这样的频道,或者使用[]字符串(字符串片段URL)。如果您只需要顺序执行,则无法从goroutine中获得任何好处,因为我们无法在goroutine启动时控制它

但是我们可以询问,然后不要等待
runtime.Gosched()

从文件: Gosched生成处理器,允许其他goroutine运行。它不会挂起当前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("")
}

就解决方案而言,我认为以现实世界中的方式解决问题没有任何好处。这并不意味着解决方案没有好处。例如,如果你在练习同步围棋,那么你就有太多的可能性进行实验和学习


因此,对我来说,这远不是一个明确的“不”,但也不是一个明确的“是”。我不想说“可能”,这取决于你到底在追求什么。你是在真正解决问题还是在学习?

我参加聚会有点晚了,但我想我还有一些东西要分享

在回答这个问题之前,我想深入探讨一下Go谚语,并发性不是parellism。人们对goroutine和Go语言特征的误解是,当人们想到goroutine时,他们会想到成为parell的能力

但正如Rob Pike在许多围棋会谈中指出的那样,围棋和goroutine实际上提供的是一致性。一致性是更好地理解现实世界的一种模式,是一种代码交互方式和结构

回到问题上来。当步骤是连续的时,是否应该使用goroutine?这取决于设计。如果您的代码由各个部分组成,彼此之间的对话非常自然,或者如果您的一些代码保留状态并且经常返回没有意义,或者如果您的代码适合任何其他Concurrency设计,则是有意义的使用goroutine和channel以及
select
语句非常好。Rob Pike再次就now Go的
text/template
使用的lexer进行了一次Go演讲,lexer使用goroutine和channel,但是解析器显然只按顺序使用lexer。他表示,使用goroutine和channel,以牺牲一点性能为代价,可以获得更好的性能实现了API


但另一方面,在您的示例中,可能是您正在考虑的(可能需要未来parellism的代码),我同意@Marc.Stick的阻塞调用,至少现在是这样。

@Flimzy-我不确定你是否忽略了这个例子,或者我不理解,但是这个例子中的每个方法都需要前一个方法的结果,所以它们不能并行执行。如果你想按顺序执行步骤,不要使用并发。并发是相反的当然。@Adrian-是的,我知道;那不是我的问题。如果你知道,那么你也知道你问题的答案。