Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save marlonfan/8a77eefe39e2af81f17704f0129c110f to your computer and use it in GitHub Desktop.
Save marlonfan/8a77eefe39e2af81f17704f0129c110f to your computer and use it in GitHub Desktop.

Revisions

  1. @AntoineAugusti AntoineAugusti revised this gist Dec 9, 2015. No changes.
  2. @AntoineAugusti AntoineAugusti revised this gist Dec 9, 2015. No changes.
  3. @AntoineAugusti AntoineAugusti revised this gist Dec 9, 2015. 1 changed file with 10 additions and 9 deletions.
    19 changes: 10 additions & 9 deletions limitConcurrentGoroutines.go
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,7 @@
    package main

    import (
    "flag"
    "fmt"
    "time"
    )
    @@ -11,16 +12,16 @@ func DoWork() {
    }

    func main() {
    // The number of goroutines that are allowed to run concurrently
    maxNbConcurrentGoroutines := 5
    // The number of jobs that we need to do
    nbJobs := 100
    maxNbConcurrentGoroutines := flag.Int("maxNbConcurrentGoroutines", 5, "the number of goroutines that are allowed to run concurrently")
    nbJobs := flag.Int("nbJobs", 100, "the number of jobs that we need to do")
    flag.Parse()

    // Dummy channel to coordinate the number of concurrent goroutines.
    // This channel should be buffered otherwise we will be immediately blocked
    // when trying to fill it.
    concurrentGoroutines := make(chan struct{}, maxNbConcurrentGoroutines)
    concurrentGoroutines := make(chan struct{}, *maxNbConcurrentGoroutines)
    // Fill the dummy channel with maxNbConcurrentGoroutines empty struct.
    for i := 0; i < maxNbConcurrentGoroutines; i++ {
    for i := 0; i < *maxNbConcurrentGoroutines; i++ {
    concurrentGoroutines <- struct{}{}
    }

    @@ -34,7 +35,7 @@ func main() {
    // Collect all the jobs, and since the job is finished, we can
    // release another spot for a goroutine.
    go func() {
    for i := 0; i < nbJobs; i++ {
    for i := 0; i < *nbJobs; i++ {
    <-done
    // Say that another goroutine can now start.
    concurrentGoroutines <- struct{}{}
    @@ -45,7 +46,7 @@ func main() {
    }()

    // Try to start nbJobs jobs
    for i := 1; i <= nbJobs; i++ {
    for i := 1; i <= *nbJobs; i++ {
    fmt.Printf("ID: %v: waiting to launch!\n", i)
    // Try to receive from the concurrentGoroutines channel. When we have something,
    // it means we can start a new goroutine because another one finished.
    @@ -62,4 +63,4 @@ func main() {

    // Wait for all jobs to finish
    <-waitForAllJobs
    }
    }
  4. @AntoineAugusti AntoineAugusti revised this gist Dec 3, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions limitConcurrentGoroutines.go
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ import (
    )

    // Fake a long and difficult work.
    func DoWork(id int) {
    func DoWork() {
    time.Sleep(500 * time.Millisecond)
    }

    @@ -54,7 +54,7 @@ func main() {
    <-concurrentGoroutines
    fmt.Printf("ID: %v: it's my turn!\n", i)
    go func(id int) {
    DoWork(id)
    DoWork()
    fmt.Printf("ID: %v: all done!\n", id)
    done <- true
    }(i)
  5. @AntoineAugusti AntoineAugusti created this gist Dec 3, 2015.
    65 changes: 65 additions & 0 deletions limitConcurrentGoroutines.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,65 @@
    package main

    import (
    "fmt"
    "time"
    )

    // Fake a long and difficult work.
    func DoWork(id int) {
    time.Sleep(500 * time.Millisecond)
    }

    func main() {
    // The number of goroutines that are allowed to run concurrently
    maxNbConcurrentGoroutines := 5
    // The number of jobs that we need to do
    nbJobs := 100
    // Dummy channel to coordinate the number of concurrent goroutines.
    // This channel should be buffered otherwise we will be immediately blocked
    // when trying to fill it.
    concurrentGoroutines := make(chan struct{}, maxNbConcurrentGoroutines)
    // Fill the dummy channel with maxNbConcurrentGoroutines empty struct.
    for i := 0; i < maxNbConcurrentGoroutines; i++ {
    concurrentGoroutines <- struct{}{}
    }

    // The done channel indicates when a single goroutine has
    // finished its job.
    done := make(chan bool)
    // The waitForAllJobs channel allows the main program
    // to wait until we have indeed done all the jobs.
    waitForAllJobs := make(chan bool)

    // Collect all the jobs, and since the job is finished, we can
    // release another spot for a goroutine.
    go func() {
    for i := 0; i < nbJobs; i++ {
    <-done
    // Say that another goroutine can now start.
    concurrentGoroutines <- struct{}{}
    }
    // We have collected all the jobs, the program
    // can now terminate
    waitForAllJobs <- true
    }()

    // Try to start nbJobs jobs
    for i := 1; i <= nbJobs; i++ {
    fmt.Printf("ID: %v: waiting to launch!\n", i)
    // Try to receive from the concurrentGoroutines channel. When we have something,
    // it means we can start a new goroutine because another one finished.
    // Otherwise, it will block the execution until an execution
    // spot is available.
    <-concurrentGoroutines
    fmt.Printf("ID: %v: it's my turn!\n", i)
    go func(id int) {
    DoWork(id)
    fmt.Printf("ID: %v: all done!\n", id)
    done <- true
    }(i)
    }

    // Wait for all jobs to finish
    <-waitForAllJobs
    }