Go语言,通道处理序列

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

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 := &lt;-c, &lt;-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(&quot;Called&quot;) 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

huangapple
  • 本文由 发表于 2015年8月24日 09:38:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/32173373.html
匿名

发表评论

匿名网友

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

确定