[英]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")
}
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)
}
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,但是值
x
和y
已经被分配了两个不同的值。 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 Spec的Assignement部分允许在以下情况下进行元组赋值:
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. 我认为这并不能保证你会得到
hello
, world
完美穿插,但我可能错了。
The reason the channel works is: 频道工作的原因是:
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.