goroutines如何运作?

时间:2014-08-28 08:28:53

标签: concurrency go goroutine

我跟随Go Tour并且在涉及到goroutines时我有点卡住了。我知道他们非常轻量级,每次goroutine阻止,另一个将开始,但我无法理解这个例子实际上是如何工作的:

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(1000 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}

Playground

据我所知,对于具有参数“world”的say函数启动了goroutine,但据我所知,应该打印“world”五次并“hello”一次。但是我不明白为什么输出是这样的:

hello
world
hello
world
hello
world
hello
world
hello

根据我对其他语言的线程的有限理解,输出应该是这样的:

hello
world
world
world
world
world

或者像这样:

world 
world
world
hello
world
world

为什么第二行也执行五次?低于go语句的任何内容都会归类为go例程的一部分吗?

下一张幻灯片还显示了一些我无法重新审视的内容:

package main

import "fmt"

func sum(a []int, c chan int) {
    sum := 0
    for _, v := range a {
        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)
}

Playground

为切片的后半部分启动goroutine,然后为切片的第一部分启动另一个goroutine,但为值xy分配了两个不同的值。我看到sum函数的方式会将它的总和发送到频道c,然后下一个sum会将它的总和发送到同一频道c那么两个怎么办呢?变量被分配两个不同的值?渠道c不应该只有一个sum值吗?

我很欣赏这是一个很长的问题,但我无法找到这些问题的答案。

2 个答案:

答案 0 :(得分:5)

  

为什么第二行也会执行5次?

第二行将在hello帖子中每隔5次打印main()同时第一行go say("world")也将在一个单独的goroutine中每隔五秒打印一次世界。
Sleep确保每个例程产生,允许另一个例程恢复。

因此输出:

hello
world
hello
world
hello
world
hello
world
hello

  

我看到它的方式sum函数会将它的总和发送到通道c,然后下一个和将它的总和发送到同一个通道c所以如何将两个变量分配给两个不同的值?

因为每次发送都会在c上阻止,直到读取频道c为止 由于有两个写入c,您需要阅读:

 x, y := <-c, <-c // receive from c twice.

Assignement section of Golang Spec允许在以下情况下进行元组分配:

  

左边的操作数必须等于右边的表达式数,每个表达式必须是单值的,右边的nth表达式分配给左边的第n个操作数。

答案 1 :(得分:1)

对于第一个函数,您应该看到VonC样式中的值。 hello打印5次的原因是因为函数say打印了5次。想象一下没有goroutine的程序。我认为它并不能保证你会完全穿插helloworld,但我可能错了。

频道有效的原因是:

  1. Golang让你做VonC提及的多项任务
  2. 频道empty out,即当您将c分配给x时,它会删除传入频道的第一笔金额,以及何时将c分配给y它传递了第二个值(我认为顺序不是保证,因为x可以有前半部分,y可以有后半部分,反之亦然。
  3. 如果你把频道想象成一种队列我觉得它更有意义。求和goroutines将值推送到队列中,赋值按顺序弹出值。

相关问题