2016-05-12 27 views
0

我会用一个黑客无效的素数查找器来使这个问题更具体。我们如何确定Go中“最后”工作进程/线程何时完成?

让我们假设我们的主要功能引发了一堆“工作人员”goroutines。他们会将结果报告给打印它们的单个通道。但是并非每个员工都会报告,所以我们不能使用计数器来知道上一份工作何时完成。还是有办法?

对于具体的例子,在这里,主要关闭goroutines来检查值2 ... 1000是否为素数(是的,我知道它是低效的)。

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    c := make(chan int) 
    go func() { 
     for { 
      fmt.Print(" ", <- c) 
     } 
    }() 
    for n := 2; n < 1000; n++ { 
     go printIfPrime(n, c) 
    } 
    time.Sleep(2 * time.Second) // <---- THIS FEELS WRONG 
} 

func printIfPrime(n int, channel chan int) { 
    for d := 2; d * d <= n; d++ { 
     if n % d == 0 { 
      return 
     } 
    } 
    channel <- n 
} 

我的问题是,我不知道如何在合适的时间可靠地停止它。我尝试在main的末尾添加一个睡眠并且它可以工作(但它可能需要很长时间,而这不是编写并发代码的方法!)。我想知道是否有办法通过某个频道发送停止信号或其他东西,因此main可以在正确的时间停止。

这里的诀窍是,我不知道会有多少员工回复。

这是不可能的还是有一个很酷的把戏?

(如果有这个典型的例子一个答案,太棒了。我也许可以概括。或者,也许不是。也许这是应用特定的?)

回答

3

使用WaitGroup

以下代码使用两个WaitGroups。主要功能使用wgTest等待print_if_prime函数完成。一旦完成,它将关闭通道以打破打印程序中的for循环。主要功能使用wgPrint等待打印完成。

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    c := make(chan int) 
    var wgPrint, wgTest sync.WaitGroup 

    wgPrint.Add(1) 
    go func(wg *sync.WaitGroup) { 
    defer wg.Done() 
    for n := range c { 
     fmt.Print(" ", n) 
    } 
    }(&wgPrint) 

    for n := 2; n < 1000; n++ { 
    wgTest.Add(1) 
    go print_if_prime(&wgTest, n, c) 
    } 

    wgTest.Wait() 
    close(c) 
    wgPrint.Wait() 
} 

func print_if_prime(wg *sync.WaitGroup, n int, channel chan int) { 
    defer wg.Done() 
    for d := 2; d*d <= n; d++ { 
    if n%d == 0 { 
     return 
    } 
    } 
    channel <- n 
} 

playground example

+0

这是利用等待的用户组_really_很好的例子。 –

相关问题