Go Channel – 我的代码看起来是在覆盖通道,但是却能正常工作。

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

Go Channel - My code looks overwriting channels but works.

问题

我最近刚开始学习Go语言,当我学习Goroutine时感到困惑。以下是我的代码,旨在同时完成3个进程。

package main

import (
	"fmt"
	"log"
	"time"
)

func wait1(c chan string) {
	time.Sleep(1 * time.Second)
	log.Print("waited 1 sec")
	c <- "wait1 finished\n"
}

func wait2(c chan string) {
	time.Sleep(2 * time.Second)
	log.Print("waited 2 sec")
	c <- "wait2 finished\n"
}

func wait3(c chan string) {
	time.Sleep(3 * time.Second)
	log.Print("waited 3 sec")
	c <- "wait3 finished\n"
}

func main() {
	c := make(chan string, 3)
	log.Print("started")
	go wait1(c)
	go wait2(c)
	go wait3(c)
	w1, w2, w3 := <-c, <-c, <-c
	log.Print("finished")
	fmt.Println(w1, w2, w3)
}

对我来说,这部分代码将不同的函数输入到名为c的相同通道中,并尝试打印从c接收到的值。

然而,正如你所看到的,输出结果是我所期望的。它同时处理3个函数,并返回"finished"语句。

为什么不需要创建3个不同的通道,比如c1c2c3...?
为什么即使我使用相同的通道c,值也不会被覆盖?

英文:

I just started learning Go recently and I was confused when I learning Goroutine.
Here's my code. This intends to finish 3 processes concurrently.

package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;time&quot;
)

func wait1(c chan string) {
	time.Sleep(1 * time.Second)
	log.Print(&quot;waited 1 sec&quot;)
	c &lt;- &quot;wait1 finished\n&quot;

}

func wait2(c chan string) {
	time.Sleep(2 * time.Second)
	log.Print(&quot;waited 2 sec&quot;)
	c &lt;- &quot;wait2 finished\n&quot;
}

func wait3(c chan string) {
	time.Sleep(3 * time.Second)
	log.Print(&quot;waited 3 sec&quot;)
	c &lt;- &quot;wait3 finished\n&quot;
}

func main() {
	c := make(chan string, 3)
	log.Print(&quot;started&quot;)
    go wait1(c)
    go wait2(c)
    go wait3(c)
    w1, w2, w3 := &lt;-c, &lt;-c, &lt;-c
    log.Print(&quot;finished&quot;)
    fmt.Println(w1, w2, w3)
}

For me, this part looks inputting different functions into the same channel called c and trying to print the values received from c.

c := make(chan string, 3)
log.Print(&quot;started&quot;)
go wait1(c)
go wait2(c)
go wait3(c)
w1, w2, w3 := &lt;-c, &lt;-c, &lt;-c
log.Print(&quot;finished&quot;)
fmt.Println(w1, w2, w3)

However, as you can see, output is what I expected. It processes 3 functions at the same time and returns "finished" statement.

2015/11/25 09:41:31 started
2015/11/25 09:41:32 waited 1 sec
2015/11/25 09:41:33 waited 2 sec
2015/11/25 09:41:34 waited 3 sec
2015/11/25 09:41:34 finished
wait1 finished
wait2 finished
wait3 finished

Why it's unnecessary to create 3 different channels like c1, c2, c3...?
Why value is not overwritten even though I'm using the same channel called c?

答案1

得分: 0

据我理解,你将通道视为一个变量,一个可以保存某个值的变量。所以,如果有一个 value1,然后你又写了一个 value2,你基本上期望 value1 会消失。这是错误的。

试着将通道看作是一个缓冲区或优先级队列(有些人觉得这个比较粗糙)。通道有它的大小(你的第三个变量 3),它告诉你可以同时在其中保存多少个值。一旦你将某个东西放入通道中,你可以将其视为具有与完成此 Go 协程所需时间相等的优先级进行处理。

所以在你的情况下,你使用 go wait() 将3个元素放入了优先级队列中,然后使用 w1, w2, w3 := <-c, <-c, <-c 从队列中提取出来。所以没有任何内容被覆盖。

英文:

As far as I understood, you view channels as a variable. A variable that can hold some value. So if there was some value1 and you wrote another value2 you basically expect the value1 to disappear. Which is wrong.

Try to take a look at the channels as a buffer or a priority queue (some people find it crude comparison). Channel has it's size (your third variable 3) which tells how many values can be simultaneously in it. Once you put something in the channel, you can view it as being processes with the priority equal to amount of time needed to finish this go-routine.

So in your case you put 3 elements in your priority queue with go wait() and then extracted from a queue with w1, w2, w3 := &lt;-c, &lt;-c, &lt;-c. So nothing gets overwritten.

答案2

得分: 0

无缓冲通道在发送数据之前会进行同步。因此,在这种情况下,你在赋值行中连续调用<-c的操作会被阻塞,直到另一端的等待函数发送数据。

不过,Markus提出了一个很好的观点,需要指出的是,这个w1, w2, w3 := <-c, <-c, <-c只能工作是因为你已经将不同的等待函数的等待时间错开了。如果这些函数在发送数据之前等待了任意的时间,你就无法保证w2被赋值为来自wait2的结果。它只会被设置为通过通道发送的第二个值。

英文:

Unbuffered channels sync before sending data through. So in this case, your successive calls to &lt;-c in your assignment line block until the wait functions on the other end sends something through.

Markus makes an excellent point though and it should be pointed out that this w1, w2, w3 := &lt;-c, &lt;-c, &lt;-c only works because you've staggered the wait times for your different wait functions. If those functions waited an arbitrary amount of time before sending data on the channel, you would not have any guarantee that w2 gets assigned to the result sent from wait2. It would just be set to which ever value was the second value sent through the channel.

huangapple
  • 本文由 发表于 2015年11月25日 08:54:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/33906721.html
匿名

发表评论

匿名网友

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

确定