golang:关于协程和通道的奇怪问题

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

golang: strange issue with coroutines and channels

问题

我写了一个测试代码,但不明白为什么会得到这个结果。

我的 sub() 函数应该根据通道的值更新或返回 counter

发送 1 = counter++
发送 0 = 返回 counter

我启动了 10 个 con() 协程。它们应该简单地向通道发送很多个 1(这会增加 counter 的值)。
我等待 1 秒钟,然后向通道发送 0。我应该得到什么值?

我认为首先会得到一个“随机”的值,
但我得到了 100000(好吧,10 乘以 10000 比 1 秒钟更快)。

现在我将

for i:=0; i < 10; i++ {

改为

for i:=0; i < 10000; i++ {

现在我的返回值是 1

为什么!?

现在取消 main() 函数中的 fmt.Println(counter) 的注释。
你会看到 counter 起作用,并且有这个“随机”的数字。

package main

import (
	"fmt"
	"time"
)

var ch chan int = make(chan int)
var counter int

func main() {
	go sub()

	for i:=0; i < 10; i++ { // 改为 10000
		go con()
	}

	time.Sleep(1000 * time.Millisecond)

	ch <- 0
	fmt.Println(<- ch)
	//fmt.Println(counter) // 取消此行的注释
}

func sub() {
	for c := range ch {
		if c == 0 { ch <- counter }
		if c == 1 {	counter++ }
	}
}

func con() {
	for i := 0; i < 10000; i++ {
		ch <- 1
	}
}
英文:

I wrote a test code, but do not understand why I get this result.

My sub() should update or return counter, based on the channel value

send 1 = counter++
send 0 = return counter

I start 10 go routines con().
They should simply send many 1 to channel (this increase counter)
I wait 1 sec and send 0 to channel. What value should I get?

I think first, I get a "random" value,
but i get 100000 (ok 10x 10000 is faster than 1 sec)

Now I change

for i:=0; i &lt; 10; i++ {

to

for i:=0; i &lt; 10000; i++ {

and now my returned value is 1

Why!?

Now uncomment fmt.Println(counter) in main().
As you see counter works and has this "random" number

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

var ch chan int = make(chan int)
var counter int

func main() {
	go sub()

	for i:=0; i &lt; 10; i++ { //change to 10000
		go con()
	}

	time.Sleep(1000 * time.Millisecond)

	ch &lt;- 0
	fmt.Println(&lt;- ch)
	//fmt.Println(counter) //uncomment this
}

func sub() {
	for c := range ch {
		if c == 0 { ch &lt;- counter }
		if c == 1 {	counter++ }
	}
}

func con() {
	for i := 0; i &lt; 10000; i++ {
		ch &lt;- 1
	}
}

答案1

得分: 0

使用2个通道,这段代码的作用是:

package main

import (
    "fmt"
    "time"
)

var ch chan int = make(chan int)
var ch2 chan int = make(chan int)
var counter int

func main() {
    go sub()

    for i := 0; i < 10000; i++ { //更改为10000
        go con()
    }

    time.Sleep(1000 * time.Millisecond)

    ch2 <- 0
    fmt.Println(<-ch2)
    //fmt.Println(counter) //取消注释此行
}

func sub() {
    for {
        select {
        case <-ch:
            counter++
        case <-ch2:
            ch2 <- counter
        }
    }
}

func con() {
    for i := 0; i < 10000; i++ {
        ch <- 1
    }
}

这段代码创建了两个整型通道chch2,以及一个整型变量counter。在main函数中,启动了一个sub协程和10000个con协程。sub协程通过select语句监听chch2通道的消息,并根据接收到的消息对counter进行操作。con协程向ch通道发送10000次整数1。

main函数中,通过time.Sleep函数等待一段时间,然后向ch2通道发送0,并从ch2通道接收结果并打印。最后,取消注释fmt.Println(counter)可以打印出counter的值。

英文:

with 2 channels, this work:

package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

var ch chan int = make(chan int)
var ch2 chan int = make(chan int)
var counter int

func main() {
    go sub()

    for i:=0; i &lt; 10000; i++ { //change to 10000
        go con()
    }

    time.Sleep(1000 * time.Millisecond)

    ch2 &lt;- 0
    fmt.Println(&lt;- ch2)
    //fmt.Println(counter) //uncomment this
}

func sub() {
	for ;; {
		select {
		case &lt;- ch:
			counter++
		case &lt;- ch2:
			ch2 &lt;- counter
		}
	}
}

func con() {
    for i := 0; i &lt; 10000; i++ {
        ch &lt;- 1
    }
}

huangapple
  • 本文由 发表于 2017年3月10日 05:13:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/42705505.html
匿名

发表评论

匿名网友

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

确定