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

Difference between plain go func and for loop in go func

我对 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 中处理异步任务一般有什么最佳实践吗?

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

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

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

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

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

据我所知,这不是关于

plain go func and for loop in go func

更多的是针对不同的用法。

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

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

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

    • 甚至你需要在concurrent/asynchronous函数之间进行通信运行,我想你一般不需要它。通常有更简单的模式通过使用通道来通信线程。

总结回答你的问题:

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

作为补充:

go的语句很简单,复杂的是跟channel的用法。为了更好地理解并发通信,我列出了您最好学习的清单。

  • 协程
  • 信道方向(发送/接收/单向)
  • 信道概念/行为是通信顺序 进程 (CSP)。这是某种关于 "block" 和 "proceed" 行为的 send/receive 行为。
  • 缓冲通道
  • 无缓冲通道
  • 关于频道的更多信息:)

希望这可以帮助您或其他人开始使用 goroutine 和通道以在 Golang 中处理并发。如果有人想更正我的答案或询问进一步的解释,请随意。谢谢。