Search code examples
multithreadingconcurrencygobubble-sortgoroutine

Why do my goroutines wait for each other instead of finishing when done?


I'm pretty new to Go and there is one thing in my code which I don't understand. I wrote a simple bubblesort algorithm (I know it's not really efficient ;)). Now I want to start 3 GoRoutines. Each thread should sort his array independent from the other ones. When finished, the func. should print a "done"-Message.

Here is my Code:

package main 

import (
    "fmt"
    "time" //for time functions e.g. Now()
    "math/rand" //for pseudo random numbers
)


/* Simple bubblesort algorithm*/
func bubblesort(str string, a []int) []int {
    for n:=len(a); n>1; n-- {
        for i:=0; i<n-1; i++ {
            if a[i] > a[i+1] {
                a[i], a[i+1] = a[i+1], a[i] //swap
            }
        }
    }
    fmt.Println(str+" done") //done message
    return a
}

/*fill slice with pseudo numbers*/
func random_fill(a []int) []int {
    for i:=0; i<len(a); i++ { 
        a[i] = rand.Int()
    }
    return a
}

func main() {
   rand.Seed( time.Now().UTC().UnixNano()) //set seed for rand.

   a1 := make([]int, 34589) //create slice
   a2 := make([]int, 42) //create slice
   a3 := make([]int, 9999) //create slice

   a1 = random_fill(a1) //fill slice
   a2 = random_fill(a2) //fill slice
   a3 = random_fill(a3) //fill slice
   fmt.Println("Slices filled ...")

   go bubblesort("Thread 1", a1) //1. Routine Start
   go bubblesort("Thread 2", a2) //2. Routine Start
   go bubblesort("Thread 3", a3) //3. Routine Start
   fmt.Println("Main working ...")

   time.Sleep(1*60*1e9) //Wait 1 minute for the "done" messages
}

This is what I get:

Slices filled ...
Main working ...
Thread 1 done
Thread 2 done
Thread 3 done

Should'nt Thread 2 finish first, since his slice is the smallest? It seems that all the threads are waiting for the others to finish, because the "done"-messages appear at the same time, no matter how big the slices are..

Where is my brainbug? =)

Thanks in advance.

*Edit: When putting "time.Sleep(1)" in the for-loop in the bubblesort func. it seems to work.. but I want to clock the duration on different machines with this code (I know, i have to change the random thing), so sleep would falsify the results.


Solution

  • Indeed, there is no garantee regarding the order in which your goroutines will be executed.

    However if you force the true parallel processing by explicitly letting 2 processor cores run :

    import (
        "fmt"
        "time" //for time functions e.g. Now()
        "math/rand" //for pseudo random numbers
        "runtime"
    )
    ...
    
    func main() {
       runtime.GOMAXPROCS(2)
    
       rand.Seed( time.Now().UTC().UnixNano()) //set seed for rand.
    ...
    

    Then you will get the expected result :

    Slices filled ...
    Main working ...
    Thread 2 done
    Thread 3 done
    Thread 1 done
    

    Best regards