理解代码:通过通信共享资源

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

Understanding the code : Sharing resources by communicating

问题

我一直在尝试理解这段代码:https://golang.org/doc/codewalk/sharemem/
虽然我大部分理解了通过通道传递资源的部分,但我无法理解程序中的无限循环。当"poller"函数中的"in"通道(从主函数接收)只运行3个"poller"协程时,程序如何无限执行"poller"函数?

我理解"StateMonitor"有一个带有无限循环的匿名go函数的概念。但是它不能在没有从"poller"函数接收的情况下更新"LogState"。我假设程序会无限执行对URL的GET请求。

为了确认我对所理解的内容没有错误,我通过打开和关闭WiFi来测试程序,看看日志是否会更改。令我惊讶的是,它确实会在几次迭代后停止响应我的更改,并继续显示相同的日志。那么,这意味着程序有bug吗?还是说我没有理解一些基本概念?

英文:

I've been trying to understand the code in
https://golang.org/doc/codewalk/sharemem/
Though I get most of the part about passing resources via channel, I'm unable to understand the infinite loop the program runs in. How does the program execute Poller function infinitely when the "in" channel in poller function(that receives from main function) run only 3 poller go routines ?

I get the idea of StateMonitor having anonymous go function with infinite loop. But it can't update LogState without receiving from Poller function. I'm assuming the program performs Get request to the urls infinitely.

To confirm that I'm not wrong about what I've understood, I tested the program by turning the wifi on and off to see if the log changes. To my surprise, it does, for few iterations but after that it stops responding to my change and keeps on showing the same log. So, does that mean program is buggy? Or is it that I haven't understood some fundamental concepts?

答案1

得分: 0

当程序中的“in”通道(从主函数接收)只运行3个poller go例程时,该程序如何无限执行Poller函数?

首先,程序创建了两个Poller:

for i := 0; i < numPollers; i++ {
    go Poller(pending, complete, status)
}

然后,它将三个资源发送到pending队列:

for _, url := range urls {
    pending <- &Resource{url: url}
}

每个Poller从pending队列中读取并轮询资源:

for r := range in {
    s := r.Poll()
    status <- State{r.url, s}
    out <- r
}

这段代码似乎会无限执行,但实际上它是在阻塞读取队列。所以这个循环会等待下一个值出现。

让我们来虚拟地逐步执行它:

  1. 有两个Poller在读取资源。
  2. 程序将第一个资源发送到队列。
  3. 其中一个poller获取资源并开始轮询,另一个等待。
  4. 在某个时刻,程序发送新的资源到队列。
  5. 由于第一个poller正在忙碌,第二个poller解除阻塞并开始轮询。
  6. 程序发送第三个资源并阻塞,因为两个poller都在忙碌。
  7. 当其中一个poller完成时,它获取最后一个资源并继续执行。
  8. 同时,主程序从complete队列中读取值。

for r := range in { s := r.Poll() status <- State{r.url, s} out <- r } 这段代码如何无限运行?如果它循环遍历“in”通道,并且“in”从pending队列获取资源,那么它应该在几次迭代后终止。我认为这正是我不理解的部分。

准确地说,in并不是从pending队列获取资源。in 就是 pending队列。该队列(或通道,我在这里可以互换使用)可以通过调用close来关闭,但在显式关闭之前,它被认为是活动的。从通道中读取会阻塞当前的goroutine,直到下一个值被提供。然后goroutine继续执行。

我猜你一直在将通道视为具有固定元素数量的数组。但实际上它们不是这样的。可以将它们视为具有无限元素数量的数组,但具有可能引发异常的阻塞读取操作(如果你对关闭队列的概念不熟悉,这是一个粗略的近似)

英文:

> How does the program execute Poller function infinitely when the "in" channel in poller function(that receives from main function) run only 3 poller go routines ?

So, first the program creates two Pollers:

for i := 0; i &lt; numPollers; i++ {
	go Poller(pending, complete, status)
}

then it sends three resources to pending:

for _, url := range urls {
	pending &lt;- &amp;Resource{url: url}
}

Every Poller reads from pending and polls the resource:

for r := range in {
	s := r.Poll()
	status &lt;- State{r.url, s}
	out &lt;- r
}

This code seems to be executed infinitely, but it is blocking read from a queue, generally. So this loops wait for the next value to appear.

Let's virtually step over it:

  1. There is two Pollers reading resources.
  2. Program sends first resource to the queue.
  3. One of the pollers gets the resource and start to pool. Another one waits.
  4. At some moment the program sends new resource to the queue.
  5. As the first poller is busy, the second one gets unblocked and start polling.
  6. Program sends third resource and blocks as two pollers are busy.
  7. When one of the pollers completes, it takes the last resource and continues.
  8. At the meantime, the main program reads values from the complete queue.

> for r := range in { s := r.Poll() status &lt;- State{r.url, s} out &lt;- r } How does this code run infinitely? If it loops over "in" channel, and "in" gets its resources from pending queue, it should terminate after few iterations. I think this is exactly the part that I don't understand.

To be precise, in does not gets the resources from pending queue. in is pending queue. The queue (or channel, which I use interchangeably) can be closed by calling close but until it is not closed explicitly it is considered alive. Any reading from it blocks the current goroutine until the next value will be given. Then gorotine resumes.

I suppose that you keep thinking about channels like they are array with fixed number of elements. They are not. Consider they like array with infinite number of elements but with blocking read that may throw exception (that the rough approximation of closing the queue if you are not familiar with the concept).

答案2

得分: 0

在通道上进行的发送操作会阻塞,直到该通道有可用的接收者:如果通道上没有接收者,就不能放入其他值。反之亦然:当通道不为空时,不能发送新值到通道中!因此,发送操作将等待通道再次可用。

另一方面,对于通道的接收操作会阻塞,直到该通道有可用的发送者:如果通道中没有值,接收者将被阻塞。

为了解除通道的阻塞,我们需要在一个无限循环中从通道中获取数据。

这就是为什么程序在一个无限循环中发送和读取数据的解释。

英文:

A send operation on a channel blocks until a receiver is available for the same channel: if there’s no recipient for the value on channel, no other value can be put in the channel. And the other way around: no new value can be sent in channel when the channel is not empty! So the send operation will wait until channel becomes available again.

On the other hand a receive operation for a channel blocks until a sender is available for the same channel: if there is no value in the channel, the receiver blocks.

To unblock the channel we need to pull the data from the channel in an infinite loop.

This is the explanation why the program is sending and reading data in an infinite loop.

答案3

得分: -1

这让我清楚了。Sleep函数实际上会导致无限循环。

这是一个相关的讨论链接

英文:

This makes me clear. Sleep function actually causes the infinite loop.

https://groups.google.com/forum/#!searchin/golang-nuts/sunil/golang-nuts/FSx8GmoRaNM/Nz9CdSF_zh8J][1]

huangapple
  • 本文由 发表于 2015年8月7日 19:01:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/31876138.html
匿名

发表评论

匿名网友

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

确定