I see lots of tutorials and examples on how to make Go wait for x number of goroutines to finish, but what I'm trying to do is have ensure there are always x number running, so a new goroutine is launched as soon as one ends.
Specifically I have a few hundred thousand 'things to do' which is processing some stuff that is coming out of MySQL. So it works like this:
db, err := sql.Open("mysql", connection_string) checkErr(err) defer db.Close() rows,err := db.Query(`SELECT id FROM table`) checkErr(err) defer rows.Close() var id uint for rows.Next() { err := rows.Scan(&id) checkErr(err) go processTheThing(id) } checkErr(err) rows.Close()
Currently that will launch several hundred thousand threads of processTheThing()
. What I need is that a maximum of x number (we'll call it 20) goroutines are launched. So it starts by launching 20 for the first 20 rows, and from then on it will launch a new goroutine for the next id the moment that one of the current goroutines has finished. So at any point in time there are always 20 running.
I'm sure this is quite simple/standard, but I can't seem to find a good explanation on any of the tutorials or examples or how this is done.
In the case of goroutines, since stack size can grow dynamically, you can spawn 1000 goroutines without a problem. As a goroutine starts with 8KB (2KB since Go 1.4) of stack space, most of them generally don't grow bigger than that.
Goroutines are useful when you want to do multiple things simultaneously. For example, if you have ten things you want to do at the same time, you can do each one on a separate goroutine, and wait for all of them to finish.
You can't kill a goroutine from outside. You can signal a goroutine to stop using a channel, but there's no handle on goroutines to do any sort of meta management. Goroutines are intended to cooperatively solve problems, so killing one that is misbehaving would almost never be an adequate response.
To run a function as a goroutine (as opposed to a standard synchronous function), you only need to add the go keyword before the function call. However, for the program to run the goroutines concurrently, you'll need to make one additional change.
You may find Go Concurrency Patterns article interesting, especially Bounded parallelism section, it explains the exact pattern you need.
You can use channel of empty structs as a limiting guard to control number of concurrent worker goroutines:
package main import "fmt" func main() { maxGoroutines := 10 guard := make(chan struct{}, maxGoroutines) for i := 0; i < 30; i++ { guard <- struct{}{} // would block if guard channel is already filled go func(n int) { worker(n) <-guard }(i) } } func worker(i int) { fmt.Println("doing work on", i) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With