gogoroutinego-sqlite3

Go routines not executing


The following is the code that is giving me problem. What i want to achieve is to create those many tables in parallel. After all the tables are created I want to exit the functions.

func someFunction(){
    ....
    gos := 5
    proc := make(chan bool, gos)
    allDone := make(chan bool)

    for i:=0; i<gos; i++ {
        go func() {
            for j:=i; j<len(tables); j+=gos {
                r, err := db.Exec(tables[j])

                fmt.Println(r)

                if err != nil {
                    methods.CheckErr(err, err.Error())
                }
            }
            proc <- true
        }()
    }

    go func() {
        for i:=0; i<gos; i++{
            <-proc
        }
        allDone <- true
    }()

    for {
        select {
        case <-allDone:
            return
        }
    }   
}

I'm creating two channels 1 to keep track of number of tables created (proc) and other (allDone) to see if all are done.

When i run this code then the go routine to create table starts execution but before it completes someFunction gets terminated.

However there is no problem if run the code sequentially

What is the mistake in my design pattern and also how do i correct it.


Solution

  • The usual pattern for what you're trying to achieve uses WaitGroup.

    I think the problem you're facing is that i is captured by each goroutine and it keeps getting incremented by the outer loop. Your inner loop starts at i and since the outer loop has continued, each goroutine starts at 5.

    Try passing the iterator as parameter to the goroutine so that you get a new copy each time.

    func someFunction(){
        ....
        gos := 5
        var wg sync.WaitGroup
        wg.Add(gos)
    
        for i:=0; i< gos; i++ {
            go func(n int) {
                defer wg.Done()
                for j:=n; j<len(tables); j+=gos {
                    r, err := db.Exec(tables[j])
    
                    fmt.Println(r)
    
                    if err != nil {
                        methods.CheckErr(err, err.Error())
                    }
                }
            }(i)
        }
        wg.Wait();     
    }
    

    I'm not sure what you're trying to achieve here, each goroutine does db.Exec on all the tables above the one it started with so the first one treats all the tables, the second one treats all but the first one and so on. Is this what you intended?