当尝试向已关闭的通道插入值时,请避免恐慌。

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

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 (
	&quot;fmt&quot;
	&quot;time&quot;
)

func fib() chan int {
	c := make(chan int)

	go func() {
		c &lt;- 0
		c &lt;- 1

		n, m := 0, 1
		for {
			temp := n + m
			n = m
			m = temp
			c &lt;- 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 = &lt;-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 (
    &quot;fmt&quot;
    &quot;time&quot;
)

func fib(c chan int) {
    c &lt;- 0
    c &lt;- 1

    n, m := 0, 1
    for {
        temp := n + m
        n = m
        m = temp
        c &lt;- m
        if m &gt; 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 = &lt;-c
        if !ok {
            fmt.Println(lastFib)
            break
        }
        lastFib = newFib
    }

    fmt.Println(time.Now().Sub(start))
}

huangapple
  • 本文由 发表于 2014年1月9日 14:23:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/21013011.html
匿名

发表评论

匿名网友

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

确定