纠正我的goroutines的实现

时间:2016-11-16 00:29:39

标签: go

背景:我正在尝试实现一个逻辑,该逻辑找到可以被1到20之间的所有数字整除的最小正数。我已经实现了一个顺序版本并获得了答案232792560。

问题:当我尝试在此问题上构建一些并发(请参阅未注释的代码块)时,它确实运行但从未显示任何结果。你们中的任何人都可以指导我出错的地方吗?

注意:我非常喜欢golang;而且我知道,这不是并发的最佳问题,因为不能保证我将得到最小的正数作为第一个结果。但是,我出于好奇而尝试了它。

    package main

    import(
        "fmt"
    )

    func divide(num int) bool {
        for i := 1; i <= 20; i++ {
            if num % i != 0 {
                return false
            }
        }
        return true
    }

    func main() {
        num:=0
        //simple function
        /*for {
            num++;
            result := divide(num)
                if result {
                    fmt.Println("Smallest number is: ", num)
                    break
                }
            }*/


        //go-routine
        //go-routine
    var wg sync.WaitGroup
    for {
        num++;
        wg.Add(1)
        go func(x int) {
            result := divide(x)
            if result {
                fmt.Println("Smallest number is: ", x)
                defer wg.Done()
            }

        }(num)

    }
    wg.Wait()
  fmt.Println("End.")

 }

2 个答案:

答案 0 :(得分:1)

启动无限数量的goroutine是没有意义的 - 它将比非并发解决方案表现更差。您可以尝试使用&#34;工作池&#34;模式并批量计算。

package main

import (
    "fmt"
    "runtime"
)

func divide(num int) bool {
    for i := 1; i <= 20; i++ {
        if num%i != 0 {
            return false
        }
    }
    return true
}

const step = 100000

func main() {
    result := make(chan int)
    jobs := make(chan int)
    for w := 0; w < runtime.NumCPU(); w++ {
        go func() {
            for n := range jobs {
                for i := n; i < n+step; i++ {
                    if divide(i) {
                        result <- i
                    }
                }
            }
        }()
    }
    num := 1
    for {
        select {
        case jobs <- num:
            num += step
        case x := <-result:
            fmt.Println("Smallest number is:", x)
            return
        }
    }
}

答案 1 :(得分:1)

解决问题的另一种方法是过滤器。我们的想法是将一堆goroutine与频道链接起来,并使它们过滤掉所有不通过某些测试的值。在您的情况下,您想要过滤不能被某个数字整除的数字。这是它的外观:

package main

import (
    "fmt"
)

func main() {
    in := make(chan int)
    tmp := in
    // Create filter-goroutines
    for i := 1; i <= 20; i++ {
        tmp = makeDivisor(i, tmp)
    }

    running := true

    // Now feed in all the numbers...
    for i := 1; running; i++ {
        select {

        // Check if a number passed all filters.
        case k := <-tmp:
            fmt.Printf("Answer is %d\n", k)
            close(in)
            running = false

        // Otherwise feed in the next.
        case in <- i:
        }
    }

}

func makeDivisor(n int, c chan int) chan int {
    cc := make(chan int)
    go func() {
        for i := range c {
            if i%n == 0 {
                cc <- i
            }
        }
        close(cc)
    }()
    return cc
}

这是playground。 (请注意,游乐场不会使用20个过滤器,但也可以在本地尝试。)

请注意,第一个过滤器要比进一步进入链中的过滤器做更多的工作。您可以启动更多的第一个过滤器来解决这个问题,尽管整数除法非常快,而且整个事情可能会受到当前频道通信的限制。

有效吗?

  

答案是232792560