一替代

09

1.用函数值

甲生成消费者图案干净多用一个简单的消费者函数传递,其也具有这样的优点,它可以返回一个值信令如果流产或任何其他动作是需要。

而且由于在该示例中只有一个事件要发出信号(“中止”),所以消费者功能将具有返回类型,如果需要中止则发出信号。

所以看到传递给发电机消费函数值这个简单的例子:

func generate(process func(x int) bool) { 
    for i := 0; i < 10; i++ { 
     if process(i) { 
      break 
     } 
    } 
} 

func main() { 
    process := func(x int) bool { 
     fmt.Println("Processing", x) 
     return x == 3 // Terminate if x == 3 
    } 
    generate(process) 
} 

输出(尝试在Go Playground):

Processing 0 
Processing 1 
Processing 2 
Processing 3 
processmain()

该解决方案的潜在缺点是它仅使用1个goroutine来生成和消费值。

2。与渠道

for ... range
generate()generate()generate()

而且,如果您要从消费者发信号通知发生器(例如,要中止并且不生成其他值),则可以使用例如,另一个通道,传递给发电机。由于发生器只会“监听”该通道,因此它也可以声明为发生器的只收通道。如果您只需要发送一个事件(在我们的例子中为中止),则不需要在此频道上发送任何值,只需简单的关闭即可。如果您需要发出多个事件的信号,可以通过在此频道上实际发送一个值,执行事件/操作(其中放弃可能来自多个事件中的一个)来完成。

select
abort
func generate(abort <-chan struct{}) <-chan int { 
    ch := make(chan int) 
    go func() { 
     defer close(ch) 
     for i := 0; i < 10; i++ { 
      select { 
      case ch <- i: 
       fmt.Println("Sent", i) 
      case <-abort: // receive on closed channel can proceed immediately 
       fmt.Println("Aborting") 
       return 
      } 
     } 
    }() 
    return ch 
} 

func main() { 
    abort := make(chan struct{}) 
    ch := generate(abort) 
    for v := range ch { 
     fmt.Println("Processing", v) 
     if v == 3 { // Terminate if v == 3 
      close(abort) 
      break 
     } 
    } 
    // Sleep to prevent termination so we see if other goroutine panics 
    time.Sleep(time.Second) 
} 

输出(尝试在Go Playground):

Sent 0 
Processing 0 
Processing 1 
Sent 1 
Sent 2 
Processing 2 
Processing 3 
Sent 3 
Aborting 

这种解决方案的明显优点是,它已经使用2个够程( 1生成值,1消耗/处理它们),并且使用任意数量的goroutine处理生成的值非常容易,因为生成器返回的通道可以同时用于多个goroutine - 通道同时可以安全地接收数据,不会发生数据竞争,通过设计;更多阅读:If I am using channels properly should I need to use mutexes?

二,未解决问题的答案

在goroutine上的“未捕获”恐慌将终止goroutine的执行,但不会导致资源泄漏方面的问题。但是,如果作为单独的goroutine执行的函数在非panic情况下释放其分配的资源(在非延迟语句中),那么该代码显然不会运行,并且会导致资源泄漏。

你还没有观察到这一点,因为程序在主要goroutine终止时终止(并且它不会等待其他非主要goroutine完成 - 所以你的其他goroutine没有机会恐慌)。见Spec: Program execution。

panic()recover()try-catchpanic()recover()