Home > Net >  Getting error "expected ';', found 'go'syntax" while trying to run a f
Getting error "expected ';', found 'go'syntax" while trying to run a f

Time:12-24

This is the code that I am trying to write ->

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

Count Build Screenshots return an integer and an error.

My use case is that I have multiple builds for which I want to run this function. This function is computationally expensive and takes 5 seconds for computing for a single build. Hence I wanted to use wait Groups for the same.

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
            
        }

CodePudding user response:

the go keyword starts a concurrent goroutine. It does not wait for the goroutine to complete (running concurrently is the whole point of a goroutine) and therefore it cannot provide the return value of the function.

You need to find a different way of returning the result of your goroutine. You alson need a synchronization mechanism so that you know when it is complete. A channel is the standard solution.

If you own the implementation of CountBuildScreenshots you can change that function directly. I'll assume you do not own that implementation, in which case we'll wrap CountBuildScreenshots in another function to handle the response. We'll also create a struct to hold both return values.

type countBuildScreenshotsResult struct {
   total int
   err error
}

Now we can create a channel that can be used to return that struct. We will wait on the channel when we're ready to consume the results.

results := make(chan countBuildScreenshotsResult)

Now we can invoke our goroutine:

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

Some time later in the code, we collect the result of the goroutine from the channel:

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

Running this function concurrently in its own goroutine only makes sense if you have other operations to complete while waiting for CountBuildScreenshots to return. If you will immediately wait for the results, then running in a goroutine does nothing for you. It's only if you have other operations that run concurrently, that goroutines make sense. In other words, if you end up with code like:

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

Then there's no point to the goroutine and you may as well run the operation in the same goroutine, as it will be blocked on completion anyway.

CodePudding user response:

I would wrap your function in a function that doesn't return anything but writes to a channel. Then you can read from that channel an wait for all results.

I am wrapping the loop in another goroutine to be able to close the channel after all are done writing to it.

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()

                // 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 comming 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
}
  • Related