【问题标题】:Getting error "expected ';', found 'go'syntax" while trying to run a function in separate goroutine尝试在单独的goroutine中运行函数时出现错误“预期';',发现'go'syntax”
【发布时间】:2022-01-24 17:47:30
【问题描述】:

这是我正在尝试编写的代码 ->

total ,err := go buildRepository.CountBuildScreenshots(buildId, OrgId, userID)
            if err!=nil {
                fmt.Println(err)
            }

Count Build Screenshots 返回一个整数和一个错误。

我的用例是我有多个要运行此功能的构建。此函数的计算量很大,单个构建需要 5 秒的计算时间。因此,我想使用相同的等待组。

for i := 0; i < len(builds); i++ {
            buildId := builds[i].BuildId
            buildRepository := NewBuildRepository(database.GetReadLTMSConn())
            total ,err := go (buildRepository.CountBuildScreenshots(buildId, OrgId, userID))
            if err!=nil {
                fmt.Println(err)
            }
            (builds[i]).TotalScreenshots = total
            
        }

【问题讨论】:

    标签: go goroutine


    【解决方案1】:

    go 关键字启动并发 goroutine。它不等待 goroutine 完成(并发运行是 goroutine 的整个point),因此它无法提供函数的返回值。

    你需要找到一种不同的方式来返回你的 goroutine 的结果。您还需要一个同步机制,以便您知道它何时完成。 channel 是标准解决方案。

    如果您拥有CountBuildScreenshots 的实现,您可以直接更改该功能。我假设您不拥有该实现,在这种情况下,我们将 CountBuildScreenshots 包装在另一个函数中以处理响应。我们还将创建一个结构来保存两个返回值。

    type countBuildScreenshotsResult struct {
       total int
       err error
    }
    

    现在我们可以创建一个可用于返回该结构的通道。当我们准备好使用结果时,我们将在通道上等待。

    results := make(chan countBuildScreenshotsResult)
    

    现在我们可以调用我们的 goroutine:

    go func() {
       var result countBuildScreenshotsResult
       result.total, result.err := buildRepository.CountBuildScreenshots(buildId, OrgId, userID)
       results <- result
    }()
    

    稍后在代码中,我们从通道中收集 goroutine 的结果:

    res := <-results
    if res.err != nil {
       ...
    } else {
       ...
    }
    

    仅当您在等待CountBuildScreenshots 返回时还有其他操作要完成时,在其自己的 goroutine 中同时运行此函数才有意义。如果您将立即等待结果,那么在 goroutine 中运行对您没有任何帮助。只有当你有 other 操作同时运行时,goroutines 才有意义。换句话说,如果你最终得到如下代码:

    results := make(chan Result)
    go func() {
       ...
       results <- result
    }()
    res := <- results
    

    那么 goroutine 就没有意义了,你也可以在同一个 goroutine 中运行该操作,因为无论如何它都会在完成时被阻塞。

    【讨论】:

      【解决方案2】:

      我会将您的函数包装在一个不返回任何内容但写入通道的函数中。然后您可以从该频道读取等待所有结果。

      我将循环包装在另一个 goroutine 中,以便能够在完成写入后关闭通道。

      type result struct {
          Count int
          Err   error
      }
      
      func main() {
          // the channel for the results
          c := make(chan result)
          
          // the top level goroutine waits for all
          // spawned goroutines to be done and closes the channel
          go func(c chan result) {
              // waitgroup is used to wait
              wg := &sync.WaitGroup{}
      
             // kick of the long running functions concurrently
             // in they own goroutine
              for i := 0; i < 10; i++ {
                  wg.Add(1)
                  go func(c chan result) {
                      defer wg.Done()
                      total, err = count()
                      // write the results to the channel
                      c <- result{total, err}
                  }(c)
              }
      
              // wait until all are done
              wg.Wait()
              // important, close the channel
              close(c)
          }(c)
          
      
          // range over the results as they are coming in
          // until the channel is closed
          for r := range c {
              if r.Err != nil {
                  fmt.Println(r.Err)
              } else {
                  fmt.Println(r.Count)
              }
          }
      
      }
      
      // simulate a longer running function
      func count() (int, error) {
          r := rand.Intn(10)
          time.Sleep(time.Duration(r) * time.Second)
          return 1, nil
      }
      

      【讨论】:

        猜你喜欢
        • 2022-11-30
        • 2022-01-11
        • 2013-01-01
        • 2022-01-24
        • 1970-01-01
        • 1970-01-01
        • 2013-09-17
        • 2017-04-04
        • 2018-05-28
        相关资源
        最近更新 更多