2

There are two odd things.

  1. I made 1000 numbers in slice but it just print 246,why 246?and why not 1000?

  2. if I delete "log.Println("hey")"this line,why does it just print 0?

I know it may has sync problem,but i haven't write any concurrence programs before,so any article can recommend?

import (
      "log"
      "runtime"
)

func main() {

  count := 1000
  slice := make([] int,count)
  for i := 0; i <= count-1; i++ {
   slice[i] =i
  }
  for _,v := range slice{
    go echo(v)
  }
  log.Println("hey")//if delete this line,it just print 0
  runtime.Gosched()
}


func echo(v int) {
  log.Println(v)
}
Nadeem_MK
  • 7,533
  • 7
  • 50
  • 61
Max Lau
  • 35
  • 2

2 Answers2

3

There's no guarantee that any of the go routines run before your main routine completes. When the main routine completes, your program exits without waiting for all the go routines you created to complete (or even start).

The easiest way to fix this is to allocate a synchronization channel, pass it to each echo instance, and write a token to it after your log statement. Then the main thread should read count tokens out of that channel before returning.

Keith Randall
  • 22,985
  • 2
  • 35
  • 54
  • but i called runtime.Gosched() at the end,the main() should wait until others goroutines back right? – Max Lau Nov 22 '13 at 09:18
  • 2
    @MaxLau, no, it is not like that. `runtime.Gosched()` simply asks the scheduler to pass control flow to other goroutines, but it never prevents the control flow to go back to `main`, when other goroutines also call `runtime.Gosched()` or do an equivalent action in terms of scheduling. So in fact your `Gosched()` call causes other goroutines to run for some time, and then main goroutine is run again, terminating shortly after this. – Vladimir Matveev Nov 22 '13 at 09:35
3

If you exit your main go routine, it doesn't wait for any go routines that are already running. You need to synchronize the running go routines and in my experience a sync.WaitGroup is the right general solution.

Playground

import (
    "log"
    "sync"
)

func main() {

    count := 1000
    slice := make([]int, count)
    for i := 0; i <= count-1; i++ {
        slice[i] = i
    }
    wg := new(sync.WaitGroup)
    for _, v := range slice {
        wg.Add(1)
        go echo(v, wg)
    }
    wg.Wait()
}

func echo(v int, wg *sync.WaitGroup) {
    defer wg.Done()
    log.Println(v)
}
Nick Craig-Wood
  • 52,955
  • 12
  • 126
  • 132
  • thx dude,but why can't i use runtime.Gosched() at the end of main()? it say "Gosched yields the processor, allowing other goroutines to run." – Max Lau Nov 22 '13 at 09:15
  • `runtime.Gosched()` only yields the processor briefly - when `main()` resumes it will return and the main go routine will exit, killing all the background go routines. – Nick Craig-Wood Nov 22 '13 at 21:30