1

I am trying to execute two or more go routine synchronously after finish the topic

goroutines order of execution

And I write some code to test the go routines' behaviour (I treat it like a queue, BTW the go concurrency tutorial page not really help me)

package main

import (
        "fmt"
        "sync"
)

const size = 10
var vChan chan int = make(chan int, size)

func justSend(wg *sync.WaitGroup) {
        defer wg.Done()
        for i := 1; i <= 10; i++ {
                vChan <- i
        }
}

func justPrint(wg *sync.WaitGroup) {
        defer wg.Done()
        v := <- vChan
        fmt.Printf("%4d ", v);
}

func main() {
        wg := new(sync.WaitGroup)

        go func() {
                wg.Add(1)
                go justSend(wg)
                wg.Wait()
                wg.Add(size)
                go justPrint(wg)
                wg.Wait()
                close(vChan)
        }()
}

But it print nothing, should we design a go routine always have a infinite loop in there or we can't get it work properly?

(The piece of code is prepared for my real problem on building multiple websocket connection and testing our API server's response, so...I think passing bunch of channel which has same type between different function is quite annoying, so I set it globally)

Kid Liou
  • 21
  • 4
  • Your application quits bofore you have chance to get any output. After the `go func() { ... })()` statement completes - nothing prevents the program from exiting. – zerkms Nov 13 '17 at 06:08
  • I am not sure what you are trying to accomplish, but I offer this: https://play.golang.org/p/GGx5HGOtBL – Charlie Tumahai Nov 13 '17 at 06:10
  • Thanks for @CeriseLimón playground supporting, but is that mean I need to close the channel first then I could read values from it in another go routines? – Kid Liou Nov 13 '17 at 06:48
  • 1
    Possible duplicate of [What's wrong with this golang code?](https://stackoverflow.com/questions/28958192/whats-wrong-with-this-golang-code/28958240#28958240) – icza Nov 13 '17 at 07:42
  • `wg.Add(size)` <- you're adding 10 to the waitgroup, but spawning only 1 routine that calls `wg.Done`. However, `main` returns before the routines are even finished. Try `go build -race` to see if race detector picks up on some things you missed, and use `delve` to step through everything – Elias Van Ootegem Nov 13 '17 at 14:05
  • If you're going to force them to run synchronously, why use goroutines at all? Why not just use regular function calls? – Adrian Nov 13 '17 at 14:44

2 Answers2

5

No, don't use infinite loop. Synchronization is better done with channels or the facilities of the sync package. The main() is a goroutine too (main one), so if main exits before other goroutines, your task remains unfinished. One way is to use sync.WaitGroup to wait for other goroutines to finish (see examples 1,2 and 3). Another way is using channels to wait for other goroutines to finish (see examples 4 and 5). I provide some examples so you may choose which one fits to your case:


1- One tx and multi rx (leave channel open), Try this:

package main

import (
    "fmt"
    "sync"
)

func main() {
    go tx()
    wg.Add(20)
    for i := 1; i <= 20; i++ {
        go rx()
    }
    wg.Wait()
}

func tx() {
    for i := 1; i <= 20; i++ {
        vChan <- i
    }
}

func rx() {
    defer wg.Done()
    fmt.Println(<-vChan)
}

var wg sync.WaitGroup

var vChan = make(chan int, 10)

2- One tx and one rx (leave channel open), Try this:

package main

import (
    "fmt"
    "sync"
)

func main() {
    go tx()
    wg.Add(1)
    go rx()
    wg.Wait()
}

func tx() {
    for i := 1; i <= 20; i++ {
        vChan <- i
    }
}

func rx() {
    defer wg.Done()
    for i := 1; i <= 20; i++ {
        fmt.Println(<-vChan)
    }
}

var wg sync.WaitGroup

var vChan = make(chan int, 10)

3- Closing channel to signal end of tx, Try this:

package main

import (
    "fmt"
    "sync"
)

func main() {
    go tx()
    wg.Add(1)
    go rx()
    wg.Wait()
}

func tx() {
    for i := 1; i <= 5; i++ {
        vChan <- i
    }
    close(vChan)
}

func rx() {
    defer wg.Done()
    for v := range vChan {
        fmt.Println(v)
    }
}

var wg sync.WaitGroup

var vChan = make(chan int, 10)

4- Closing channel to signal end of tx, using main goroutine for rx, try this:

package main

import (
    "fmt"
)

func main() {
    go tx()
    for v := range vChan {
        fmt.Println(v)
    }
}

func tx() {
    for i := 1; i <= 20; i++ {
        vChan <- i
    }
    close(vChan)
}

var vChan = make(chan int, 10)

5- Using quit channel, try this:

package main

import (
    "fmt"
)

func main() {
    go tx()
    go rx()
    <-quit
}
func rx() {
    for v := range vChan {
        fmt.Println(v)
    }
    quit <- struct{}{}
}
func tx() {
    for i := 10; i <= 15; i++ {
        vChan <- i
    }
    close(vChan)
}

var quit = make(chan struct{}, 1)
var vChan = make(chan int, 10)

output:

10
11
12
13
14
15

6- Multi tx multi rx, try this:

package main

import (
    "fmt"
    "sync"
)

func main() {
    wg.Add(5)
    for i := 1; i <= 5; i++ {
        go tx()
        go rx()
    }
    wg.Wait()
}

var n = 10

func tx() {
    vChan <- n
    n++
}

func rx() {
    defer wg.Done()
    fmt.Println(<-vChan)
}

var wg sync.WaitGroup

var vChan = make(chan int, 10)

7- Multi tx and one rx, try this:

package main

import (
    "fmt"
    "sync"
)

func main() {
    for i := 1; i <= 5; i++ {
        wg.Add(1)
        go tx()
    }

    go rx()
    wg.Wait()
}

func rx() {
    for {
        fmt.Println(<-vChan)
        wg.Done()
    }
}

var n = 20

func tx() {
    vChan <- n
    n++
}

var wg sync.WaitGroup

var vChan = make(chan int, 10)

I hope this helps.

wasmup
  • 14,541
  • 6
  • 42
  • 58
0

You have put goroutine in main and main function finishes before your go routine finishes. So either do not use goroutine in main or use some kind of boolean receiving channel at the end of main which gets true when goroutine completed.

kamal
  • 996
  • 15
  • 25