如果在第一次迭代和第二次迭代之间存在一个小的时刻

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

IF there is a small moment between the first iteration and the second iteration

问题

在下面的代码中,迭代运行了两次。"test2 <- true"是否可能在第一次迭代结束和第二次迭代开始之间的时刻运行?我的意思是,在第一次迭代结束时,第二次迭代还没有开始时,是否有可能将true发送到"test2"?

package main

import "log"
import "time"

func main() {
    test := make(chan bool, 1)
    test2 := make(chan bool, 1)

    go func() {
        for {
            select {
            case <-test:
                log.Println("test")
            case <-test2:
                log.Println("test2")
            }
        }
    }()

    test <- true
    time.Sleep(1)
    test2 <- true
    time.Sleep(1)
}

在这段代码中,"test2 <- true"只有在第一次迭代结束并且第二次迭代开始之后才会运行。因为在第一次迭代结束之前,程序会阻塞在case <-test:这一行,直到从"test"通道接收到一个值。只有当第一次迭代结束后,程序才会继续执行并发送true到"test2"通道。所以不会出现在第一次迭代结束和第二次迭代开始之间发送true到"test2"的情况。

英文:

In the code below, iterations are runned two times.<br>
Is it possible that "test2 <- true" is runned at the moment which is just between the first iteration and the second iteration?<br>
I mean, is there a change to send true to "test2" when the first iteration is ended and the second iteration is not started?<br>

package main

import &quot;log&quot;
import &quot;time&quot;

func main() {
	test := make(chan bool, 1)
	test2 := make(chan bool, 1)

	go func() {
		for {
			select {
			case &lt;-test:
				log.Println(&quot;test&quot;)
			case &lt;-test2:
				log.Println(&quot;test2&quot;)
			}
		}
	}()

	test &lt;- true
	time.Sleep(1)
	test2 &lt;- true
	time.Sleep(1)
}

答案1

得分: 4

是的。由于您的通道是带缓冲区的,可以容纳1个值。主执行流程可以继续进行,而不需要您的匿名goroutine读取您发送到“test”通道的值,并且它可以在goroutine唤醒并读取“test”通道上的值之前,在“test2”通道上发送一个值。

这种情况不太可能发生,因为您在那里有一个time.Sleep()调用,通常会给goroutine执行的时间,但是无法预测在机器非常繁忙、在(不)幸运的时间被暂停电源或其他您没有考虑到的情况下会发生什么。

如果您的“test”通道是无缓冲的,那么“test <- true”语句将阻塞,直到您的goroutine接收到该值,并且至少不会有可能在从“test”通道接收任何内容之前从“test2”接收。

英文:

Yes. Since your channels are buffered and can hold 1 value. the main execution flow can continue without your anonymous goroutine reading the value you send to the test channel, and it can send a value on the test2 channel before the goroutine wakes up and read the value on the test channel.

This is unlikely to happen, since you have a time.Sleep() call there to normally give time for the goroutine to execute, but there's no telling what'll happen in a corner case of your machine being very busy, being power suspended at an (un)lucky time or other things you didn't think about.

If your test channel was unbuffered, the test &lt;- true statement would block until your goroutine received the value, and there would at least be no possibility for the goroutine to receive from test2 before receiving anything from the test channel.

答案2

得分: 3

为了补充nos的回答,你可以通过让第一个消息接收(case <-test)等待一秒钟来模拟这种情况(即在第一次迭代和第二次迭代之间运行“test2 <- true”的时刻)。

case <-test:
    log.Println("test")
    time.Sleep(1 * time.Second)

当匿名goroutine醒来时,main()已经将其两个消息发送到两个缓冲通道(缓冲意味着对于一个消息不会阻塞),并退出了。
如果main()退出,包括正在休眠的goroutine在内的所有其他内容都会停止。

参见[kbd>play.golang.org</kbd>:输出将是:

2009/11/10 23:00:00 test

你将没有时间看到test2

为了确保你的goroutine能够处理两个消息,你需要:

  • main()等待goroutine完成。这就是sync发挥作用的地方,可以使用(例如,这不是唯一的解决方案)WaitGroup指令。
var wg sync.WaitGroup
wg.Add(1)
go func() {
    // goroutine完成时减少计数器。
    defer wg.Done()
    ...
}
... // main()的结尾:
// 等待goroutine完成。
wg.Wait()
loop:                                  <==========
for {
    select {
    case <-test:
        log.Println("test")
        time.Sleep(1 * time.Second)
    case <-test2:
        log.Println("test2")
        break loop                     <==========
    }
}

参见[kbd>play.golang.org</kbd>:在goroutine在test1后休眠时发送了消息test2,但是main()会等待(wg.Wait()),并且goroutine将有机会在一秒钟后读取和打印test2

输出是:

2009/11/10 23:00:00 test
2009/11/10 23:00:01 test2  // 一秒钟后
英文:

To add to nos' answer, you can simulate that case (where "test2 &lt;- true" is run at the moment which is just between the first iteration and the second iteration") easily enough by making your first message reception (case &lt;- test) wait one second.

case &lt;-test:
	log.Println(&quot;test&quot;)
	time.Sleep(1 * time.Second)

By the time the anonymous goroutine wakes up, main() has already sent its two messages to the two buffered channel (buffer means non-blokcing for one message), and exited.
If main() exits, everything else, including the goroutine which was busy sleeping, stops.

See <kbd>play.golang.org</kbd>: the output would be:

2009/11/10 23:00:00 test

You wouldn't have the time to see test2.


In order to make sure your goroutine can process both message, you need:

  • main() to wait for said goroutine to finish. That is where the sync package comes into play, using (for instance, this isn't the only solution) a WaitGroup directive.

      var wg sync.WaitGroup
      wg.Add(1)
      go func() {
      	// Decrement the counter when the goroutine completes.
      	defer wg.Done()
          ...
      }
      ... // end of main():
      // Wait for goroutine to complete.
      wg.Wait()
    
  • the goroutine to actually exit at some time (instead of being stuck in the for loop forever). See "In Go, does a break statement break from a switch/select?"

      loop:                                  &lt;==========
      for {
      	select {
      	case &lt;-test:
      		log.Println(&quot;test&quot;)
      		time.Sleep(1 * time.Second)
      	case &lt;-test2:
      		log.Println(&quot;test2&quot;)
      		break loop                     &lt;==========
      	}
      }
    

See <kbd>play.golang.org</kbd>: the message test2 is sent while the goroutine is sleeping after test1, but main() will wait (wg.Wait()), and the goroutine will have its chance to read and print test2 one second later.

The output is:

2009/11/10 23:00:00 test
2009/11/10 23:00:01 test2  // one second later

huangapple
  • 本文由 发表于 2014年7月27日 02:00:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/24973935.html
匿名

发表评论

匿名网友

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

确定