简体   繁体   English

goroutines如何运作?

[英]How do goroutines work?

I was following the Go Tour and I am a bit stuck when it comes to goroutines. 我正在关注Go Tour ,当涉及到goroutines时我有点卡住了。 I understand that they are very lightweight and that every time a goroutine blocks, another one will start but I can't get my head around how this example actually works: 我知道他们非常轻量级,每次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 操场

I understand that a goroutine is started for the say function with the argument "world", but as far as I understand that should print "world" five times and "hello" once. 据我所知,一个goroutine是针对具有参数“world”的say函数启动的,但据我所知,应该打印“world”五次并且“hello”一次。 However I don't understand why the output is as it is: 但是我不明白为什么输出是这样的:

hello
world
hello
world
hello
world
hello
world
hello

From my limited understanding of threads from other languages the output should have been something like this: 从我对其他语言的线程的有限理解,输出应该是这样的:

hello
world
world
world
world
world

or like this: 或者像这样:

world 
world
world
hello
world
world

Why does the second line execute five times as well? 为什么第二行也执行五次? Does anything below a go statement classify as part of the go routine? go语句下面的任何内容都go归类为go例程的一部分吗?

Also the next slide shows something I can't get my head round again: 下一张幻灯片还显示了我无法再次回头看的内容:

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 操场

A goroutine is started for the second half of the slice and then another one for the first part of the slice, however the values x and y have been assigned two different values. 对于切片的后半部分开始goroutine,然后为切片的第一部分开始另一个goroutine,但是值xy已经被分配了两个不同的值。 The way I see it the sum function will send it's sum to channel c and then the next sum will send it's sum to the same channel c so how can the two variables be assigned two different values? 我看到它的方式sum函数将它的总和发送到通道c ,然后下一个sum将它的总和发送到相同的通道c那么如何为这两个变量分配两个不同的值? Shouldn't channel c have one single sum value in there? 通道c不应该有一个单一的sum值吗?

I appreciate that this is quite a long question but I wasn't able to find the answer to these questions. 我很欣赏这是一个很长的问题,但我无法找到这些问题的答案。

Why does the second line execute 5 times as well? 为什么第二行也执行5次?

The second line will print hello every second 5 times in the main() thread. 第二行将在main()线程中每隔5次打印hello
But concurrently the first line go say("world") will also print world every seconds five times in a separate goroutine. 同时第一行go say("world")也将在一个单独的goroutine中每秒打印五次世界。
The Sleep ensure that each routine yields, allowing the other to resume. Sleep确保每个例程产生,允许另一个例程恢复。

Hence the output: 因此输出:

hello
world
hello
world
hello
world
hello
world
hello

The way I see it the sum function will send it's sum to channel c and then the next sum will send it's sum to the same channel c so how can the two variables be assigned two different values? 我看到它的方式sum函数将它的总和发送到通道c,然后下一个和将它的总和发送到相同的通道c,那么如何为这两个变量分配两个不同的值?

Because each send will block on c until channel c is read. 因为每个发送都将在c阻塞,直到读取通道c
Since there are two write to c , you need to read: 由于有两个写入c ,您需要阅读:

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

The Assignement section of Golang Spec allows for a tuple assignment if: Golang SpecAssignement部分允许在以下情况下进行元组赋值:

the number of operands on the left must equal the number of expressions on the right, each of which must be single-valued, and the nth expression on the right is assigned to the nth operand on the left. 左边的操作数数量必须等于右边的表达式数量,每个表达式必须是单值,右边的nth表达式分配给左边的第n个操作数。

For the first function you should see values in the style VonC presented. 对于第一个函数,您应该看到VonC所呈现的值。 The reason hello prints 5 times as well is because the function say prints things 5 times. hello打印5次的原因是因为函数say打印东西5次。 Just imagine the program without the goroutine. 想象一下没有goroutine的程序。 I think it doesn't guarantee that you will get hello and world perfectly interspersed but I may be wrong. 我认为这并不能保证你会得到helloworld完美穿插,但我可能错了。

The reason the channel works is: 频道工作的原因是:

  1. Golang let's you do multiple assignment as VonC mentions Golang让你做VonC提到的多项任务
  2. Channels empty out , ie when you assign c to x it removes the first sum that was passed into the channel and when it assigns c to y it passes in the second value (again I think the order is not a guarantee as x could have the first half and y the second half sum or vice-versa. empty out通道,即当你将c分配给x它会移除传递给通道的第一个总和,当它将c分配给y它传递给第二个值(再次我认为顺序不是保证,因为x可以具有第一半部和y下半年总和或反之亦然。

If you imagine channels as a sort of a queue I think it makes more sense. 如果你把频道想象成一种队列我觉得它更有意义。 The summing goroutines push values onto the queue and assignments pop the values sequentially. 求和goroutines将值推送到队列,并且赋值按顺序弹出值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM