在处理 goroutine 时有一个奇怪的问题。

huangapple go评论78阅读模式
英文:

Odd thing when deal with goroutine

问题

有两个奇怪的事情。

  1. 我在切片中创建了1000个数字,但只打印了246,为什么是246?为什么不是1000?

  2. 如果我删除"log.Println("hey")"这一行,为什么只打印0?

我知道可能存在同步问题,但我以前没有编写过并发程序,有没有什么文章可以推荐?

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") // 如果删除这一行,它只会打印0
    runtime.Gosched()
}

func echo(v int) {
    log.Println(v)
}
英文:

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 (
      &quot;log&quot;
      &quot;runtime&quot;
)

func main() {

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


func echo(v int) {
  log.Println(v)
}

答案1

得分: 3

没有任何保证任何go例程在主例程完成之前运行。当主例程完成时,你的程序会退出,而不会等待你创建的所有go例程完成(甚至开始)。

修复这个问题的最简单方法是分配一个同步通道,将其传递给每个echo实例,并在日志语句之后向其写入一个令牌。然后,主线程应该在返回之前从该通道中读取count个令牌。

英文:

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.

答案2

得分: 3

如果你退出主要的go routine,它不会等待任何已经在运行的go routine。你需要同步正在运行的go routine,在我看来,sync.WaitGroup 是一个正确的通用解决方案。

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)
}
英文:

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 (
	&quot;log&quot;
	&quot;sync&quot;
)

func main() {

	count := 1000
	slice := make([]int, count)
	for i := 0; i &lt;= 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)
}

huangapple
  • 本文由 发表于 2013年11月22日 15:01:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/20138950.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定