Datsik
Datsik

Reputation: 14824

How can I do multiple concurrent requests properly?

Hi guys I'm trying to make multiple requests to a database, and I found doing them in order synchronously is quite slow and exponentially increases response time while waiting for each request to finish, this is what I have so far:

var wg sync.WaitGroup
dbUsername := make(chan string, 1)
dbEmail := make(chan string, 1)

wg.Add(2)
go func(username chan string, waiter sync.WaitGroup) {
    defer waiter.Done()
    err = db.QueryRow("SELECT username FROM user WHERE username = ?", vals.Get("username")).Scan(&result)
    if err != nil {
        log.Println(err)
    }
}(dbUsername, wg)

go func(email chan string, waiter sync.WaitGroup) {
    defer waiter.Done()
    err = db.QueryRow("SELECT email FROM user WHERE email = ?", vals.Get("email")).Scan(&result)
    if err != nil {
        log.Println(err)
    }
}(dbEmail, wg)

wg.Wait()



if <-dbUsername != "" {
    formErrors = append(formErrors, "Username has already been taken.")
}
if <-dbEmail != "" {
    formErrors = append(formErrors, "Email has already been taken.")
}

but it doesn't seem to work correctly, I've followed the WaitGroup example to the dot, but it seems to hang on wg.Wait() and I'm not sure why. And is there a prettier way to do this or is what I have mocked up normal?

also small sub question:

is it possible to declare a buffered channel with var e.g. var blah chan string 1

Upvotes: 0

Views: 113

Answers (1)

nos
nos

Reputation: 229068

You're passing in a copy of your WaitGroup to your two functions,

Instead pass in a pointer, waiter *sync.WaitGroup, so your code that waits on the WaitGroup and the goroutines all operates on the same WaitGroup.

This is also noted in the documentation:

Values containing the types defined in this package should not be copied.

However, in your case your goroutine functions can access the variables declared in the outer scope, so you don't need to pass in any arguments at all. You might not need the WaitGroup either, as receiving of <-dbUsername and <-dbEmail will anyway wait until the goroutines are done - as long as you make both your goroutines send a value on their respective channels. And you don't need buffered channels here either.

As for this:

is it possible to declare a buffered channel with var e.g. var blah chan string 1

Yes, remember that channels need to be created using make()

var blah chan string 
blah = make(chan string, 1)

Or var blah chan string = make(chan string, 1)

Upvotes: 1

Related Questions