英文:
Go lang, channel processing sequence
问题
我正在通过《Go之旅》学习Go语言,但是很难理解Go通道的运行顺序。
第一个例子中,如果运行上述代码,我期望的输出是:
Print this first,
17 -5 12
因为Go协程是非阻塞运行的。但实际上,它输出的结果是:
17 -5 12
Print this first,
在第二个例子中,我在互联网上找到了另一个例子。如果运行以下代码,我期望的输出是:
Called
10
20
20
但实际上,输出结果是:
10
20
20
Called
我对这些代码的理解有误吗?请帮助我理解Go协程和通道。
英文:
I'm studying Go lang through 'A tour of Go', and it's hard to understand Go channel running sequence,
package main
import "fmt"
import "time"
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
time.Sleep(1000 * time.Millisecond)
sum += v
}
c <- sum // send sum to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
fmt.Println("Print this first,")
}
If run above the code, I expected,
Print this first,
17 -5 12
Because, Go routine runs as non-blocking, a But, actually it prints,
17 -5 12
Print this first,
The other example that I found in internet,
package main
import "fmt"
type Data struct {
i int
}
func func1(c chan *Data ) {
fmt.Println("Called")
for {
var t *Data;
t = <-c //receive
t.i += 10 //increment
c <- t //send it back
}
}
func main() {
c := make(chan *Data)
t := Data{10}
go func1(c)
println(t.i)
c <- &t //send a pointer to our t
i := <-c //receive the result
println(i.i)
println(t.i)
}
Also, I expected, it prints "Called" first, but the result is
10
20
20
Called
What I am misunderstanding? please help me to understand Go routine and channel.
答案1
得分: 3
在你的第一个例子中,x, y := <-c, <-c
会阻塞直到两次从 c
中读取到值,然后将这些值赋给 x, y
。除了通道操作之外,你有一个赋值语句,一个打印语句,然后是另一个打印语句。这些都是同步的操作,将按照你指定的顺序进行。第二个打印语句不可能先于第一个打印语句执行。
第二个例子是因为 fmt.Println
写入标准输出(STDOUT),而 println
写入标准错误(STDERR)。如果你保持一致(比如在所有地方都使用 println
),你会看到以下结果:
10
Called
20
20
这是因为主函数中的第一个 println(t.i)
和 goroutine 中的 println("Called")
之间存在竞争。我猜测在将 GOMAXPROCS
设置为 1 的情况下,这种情况会一直发生。将 GOMAXPROCS
设置为 NumCPU
时,我得到了各种结果,有时看起来像上面的结果,有时看起来像这样:
10Called
20
20
英文:
In your first example, x, y := <-c, <-c
will block until it reads off c
twice, and then assign values to x, y
. Channels aside, you have an assignment, a print statement, then another print statement. Those are all synchronous things, and will happen in the order you state them in. There's no way the second print statement would print first.
The second one is because fmt.Println
writes to STDOUT and println
to STDERR. If you are consistent (say use println
everywhere) then you see:
10
Called
20
20
That's cause there's a race between the first println(t.i)
in the main and the println("Called")
that's happening in the goroutine. I'm guessing with GOMAXPROCS
set to 1, this will happen consistently. With GOMAXPROCS
set to NumCPU
, I get a mix of results, sometimes looking like the above, and sometimes like this:
10Called
20
20
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论