我有以下代码片段。
package main import ( "errors" "fmt" "time" ) func errName(ch chan error) { for i := 0; i < 10000; i++ { } ch <- errors.New("Error name") close(ch) } func errEmail(ch chan error) { for i := 0; i < 100; i++ { } ch <- errors.New("Error email") close(ch) } func main() { ch := make(chan error) go errName(ch) go errEmail(ch) fmt.Println(<-ch) //close(ch) time.Sleep(1000000) }
如您所见,我在goroutine中运行了两个函数errName和errEmail。我将错误类型的通道作为参数传递。如果其中一个先完成,它应该通过通道发送错误并关闭它。因此,第二个仍在运行的goroutine不再需要运行,因为我已经遇到了错误,并且我想终止仍在运行的goroutine。这就是我在上面的示例中尝试达到的目标。
当我运行程序时,出现错误
panic: send on closed channel goroutine 6 [running]: main.errEmail(0xc0820101e0) D:/gocode/src/samples/gorountine2.go:24 +0xfd created by main.main D:/gocode/src/samples/gorountine2.go:33 +0x74 goroutine 1 [runnable]: main.main() D:/gocode/src/samples/gorountine2.go:34 +0xac exit status 2
我知道,当我删除close语句时,它不会死机,但是正在运行的goroutine上的通道仍在等待错误引用,这意味着,它浪费了内存,没有任何等待。
当其中一个向通道发送错误时,我不再关心第二个错误,那就是我的目标。
组织这种行为的标准方法是使用
package main import ( "fmt" "time" "code.google.com/p/go.net/context" ) func errName(ctx context.Context, cancel context.CancelFunc) { for i := 0; i < 10000; i++ { select { case <-ctx.Done(): return default: } } cancel() } func errEmail(ctx context.Context, cancel context.CancelFunc) { for i := 0; i < 100; i++ { select { case <-ctx.Done(): return default: } } cancel() } func main() { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) go errName(ctx, cancel) go errEmail(ctx, cancel) <-ctx.Done() if ctx.Err() != nil { fmt.Println(ctx.Err()) } time.Sleep(1000000) }
您可以阅读有关此问题的两篇好文章: