英文:
Avoid panic, when trying to insert a value to a closed channel
问题
以下是代码的中文翻译:
package main
import (
"fmt"
"time"
)
func fib() chan int {
c := make(chan int)
go func() {
c <- 0
c <- 1
n, m := 0, 1
for {
temp := n + m
n = m
m = temp
select {
case c <- m:
case <-c:
return
}
}
}()
return c
}
func main() {
start := time.Now()
var lastFib int
c := fib()
for i := 0; i != 1000000; i++ {
lastFib = <-c
}
close(c)
fmt.Println(lastFib)
fmt.Println(time.Now().Sub(start))
}
在最符合惯用方式的情况下,如何避免在通道关闭时引发 panic?或者我应该完全避免使用 close
?我不想使用其他方法(如闭包)来实现相同的功能,只是想更好地理解通道。
英文:
package main
import (
"fmt"
"time"
)
func fib() chan int {
c := make(chan int)
go func() {
c <- 0
c <- 1
n, m := 0, 1
for {
temp := n + m
n = m
m = temp
c <- m // This results in panic, when the channel is closed
}
}()
return c
}
func main() {
start := time.Now()
var lastFib int
c := fib()
for i := 0; i != 1000000; i++ {
lastFib = <-c
}
close(c)
fmt.Println(lastFib)
fmt.Println(time.Now().Sub(start))
}
In the most idiomatic way, how would one avoid the panic in the goroutine, when the channel is closed? Or should i avoid using close
at all?
I'm not looking into alternative methods (such as closures) to achieve the same thing, just trying to get a better understanding of channels.
答案1
得分: 7
“Close”是一种很好的方式,用于让发送到通道中的goroutine向接收方信号传达完成对该通道的操作。相反的方式(你的问题)在我看来是不可行的,至少是直接的方式。你可以添加另一个通道done
,用于向生成斐波那契数的goroutine发送结束信号。
英文:
Close
is a good way for the goroutine sending into a channel to signal the receiving side that you are done with this channel. The other way around (your problem) is IMHO undoable, at least direct. You could add an other channel done which signal end of duty to your fibonacci generating goroutine.
答案2
得分: 1
这是一个修改过的示例代码,它以一种允许的方式(尽管不一定合理)使用了通道:
package main
import (
"fmt"
"time"
)
func fib(c chan int) {
c <- 0
c <- 1
n, m := 0, 1
for {
temp := n + m
n = m
m = temp
c <- m
if m > 100000000 {
close(c)
break
}
}
}
func main() {
start := time.Now()
lastFib, newFib := 0, 0
ok := true
c := make(chan int)
go fib(c)
for {
newFib, ok = <-c
if !ok {
fmt.Println(lastFib)
break
}
lastFib = newFib
}
fmt.Println(time.Now().Sub(start))
}
这段代码使用通道来生成斐波那契数列,并在斐波那契数列的值超过100000000后关闭通道。在main
函数中,我们创建了一个通道c
,并启动一个协程来执行fib
函数。然后,我们通过从通道c
接收值来获取斐波那契数列的每个值,直到通道关闭。最后,我们打印出程序的运行时间。
请注意,这段代码中的通道用法可能不太合理,仅供参考。
英文:
Here is a modified version of your example that uses channels in an allowed (though not necessarily sensible) way:
package main
import (
"fmt"
"time"
)
func fib(c chan int) {
c <- 0
c <- 1
n, m := 0, 1
for {
temp := n + m
n = m
m = temp
c <- m
if m > 100000000 {
close(c)
break
}
}
}
func main() {
start := time.Now()
lastFib, newFib := 0, 0
ok := true
c := make(chan int)
go fib(c)
for {
newFib, ok = <-c
if !ok {
fmt.Println(lastFib)
break
}
lastFib = newFib
}
fmt.Println(time.Now().Sub(start))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论