英文:
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 "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)
}
答案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 <- 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能够处理两个消息,你需要:
var wg sync.WaitGroup
wg.Add(1)
go func() {
// goroutine完成时减少计数器。
defer wg.Done()
...
}
... // main()的结尾:
// 等待goroutine完成。
wg.Wait()
- goroutine实际上在某个时间退出(而不是永远被困在
for
循环中)。参见“在Go中,break语句是否会从switch/select中跳出?”。
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 <- 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 <- test
) wait one second.
case <-test:
log.Println("test")
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 thesync
package comes into play, using (for instance, this isn't the only solution) aWaitGroup
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: <========== for { select { case <-test: log.Println("test") time.Sleep(1 * time.Second) case <-test2: log.Println("test2") break loop <========== } }
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论