【问题标题】:Difference between plain go func and for loop in go funcgo func 中的普通 go func 和 for 循环之间的区别
【发布时间】:2018-06-30 15:31:15
【问题描述】:

我对 go func 中的普通 go func 和 for 循环之间的区别有一些疑问:

  1. 普通函数:

    func asyncTask(){
        //...something
    }
    

    为了触发asyncTask,我们可以很简单:

    func main(){
        go asyncTask()
    }
    
  2. 创建一个for循环来监控通道:

    func (c *Container) asyncTask(){
        go func(){
            for {
                select {
                    case <- c.someChan:
                        //...do something
                    case <-c.ctx.Done():
                        //...prevent leaking
                }
            }
        }()
    }
    

    触发:

    func (c *Container) trigger(){
        c.someChan <- val
    }
    

我的问题是:

  1. 我理解第二种情况最适合我们希望在队列中管理异步任务的情况。 但是对于频繁触发的异步任务(不能被阻塞)的性能,哪种方法更好?

  2. 一般来说,在 GoLang 中处理异步任务是否有任何最佳实践?

【问题讨论】:

    标签: go channel goroutine


    【解决方案1】:

    几乎在任何情况下,性能都不是选择使用哪种模式时要考虑的事情(两者都可以),而是在您的特定用例中哪种用法有意义。如果使用模式 (1),则不能保证 (2) 的顺序处理。这是您的两个示例之间的本质区别。因此,以 http 服务器为例,您将使用前一种模式(go handleRequest(r HttpRequest) 说)并行处理请求,但使用后者确保某些操作是按顺序处理的。我希望这能回答你的问题!

    【讨论】:

      【解决方案2】:

      当你有需要考虑的 goroutine 并且只关心它们的退出时,你可以将模型 #1 与 WaitGroups 一起使用,因此不需要管理等。

      当您需要明确的管理/控制/通信时,您可以使用模型 #2。通道通信不是免费的——发送和接收例程需要同步/通道需要在发送值时锁定,很多事情都必须在幕后发生。

      除非需要,否则绝对是选项#1。看看你的问题最简单的解决方案是什么 - 我知道说教很容易,但简单可能需要一些时间。

      【讨论】:

        【解决方案3】:

        简而言之,据我所知,您上面提到的 2 种模式并不是真正比较使用哪一种或哪一种更好的东西。它们只是有不同的用例和不同的必要性。

        据我所知,这不是关于

        go func 中的普通 go func 和 for 循环

        更多的是不同的用法。

        在回答您的问题之前,我想尝试对您提到的两种模式进行简短的解释。

        1. 第一个模式是一个非常基本的go 语句用法。它将在其主线程之外执行函数。作为 go 中并发的基本用法,这种模式设计无法使用go 语句从执行的函数中获取数据。不能来自main() 线程或任何其他函数。为了与任何其他函数/线程通信,它需要channel。您已经提到了 一个 模式,该模式来自多个 gochannel 模式可用。
        2. 就像我之前提到的,第二个模式只是 Golang 中的几个 gochannel 模式之一,与 go 语句一起使用。实际上,这是一个相当复杂的模式,主要用于从多个渠道中选择,并将对这些渠道做进一步的事情。我将对此模式进行一些简单的解释,如下所示:

          • for 循环没有条件语句,它在 C 或 Java 等任何其他语言中的工作方式与 while 循环类似。这意味着一个无限循环。
          • 由于它是无限循环,因此需要一个通常从可用通道中检查的条件来检查。例如,当频道关闭时,它就会结束。
          • 关于selectcase语句,如果同时准备好两个或多个通信案例,则随机选择一个

          • 即使您需要在运行的并发/异步函数之间进行通信,我想您通常也不需要它。通常有更简单的模式通过使用通道来通信线程。

        总结回答您的问题:

        1. 哪种方法更好地执行异步任务实际上取决于您的需要。上面提到的有几种不限于你的模式。如果您只需要异步执行函数,第一个模式就可以了,否则您需要一个来自channel 模式的可用方式。但同样,不限于您上面提到的第二种模式
        2. 您提到的两种模式对我来说都是常见的做法。但我想通常我们通常至少需要一个channel 才能与main() 线程或任何其他线程通信异步任务。它本身的模式实际上取决于您将如何通信(发送/接收)数据/值源(数据库、切片变量等)以及更多其他方面。我建议您更多地了解channel 的用法,有很多模式与此有关。我建议先检查一下https://gobyexample.com/goroutines。从那里开始,您会在页面底部看到“下一个示例”,它将更深入地了解 Go 并发的事情。

        作为补充:

        go 语句很简单,复杂的事情是关于channel 的用法。为了更好地理解并发通信,我列出了你更好地学习的列表。

        • 协程
        • 通道方向(发送/接收/单向)
        • 按顺序进行通信的渠道概念/行为 流程 (CSP) 。它是某种关于发送/接收行为的“阻止”和“继续”行为。
        • 缓冲通道
        • 无缓冲通道
        • 关于频道的更多信息:)

        希望这可以帮助您或其他人从 goroutine 和 channel 开始在 Golang 中使用并发。如果有人想对我的答案进行更正或要求进一步解释,请随意。谢谢。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-09
          • 1970-01-01
          • 2013-10-20
          • 2022-01-09
          • 2018-03-21
          • 1970-01-01
          相关资源
          最近更新 更多