Golang:使用 buffered channel 实现生产者消费者模式

43 阅读1分钟

任务是一个Golang 的面试题:找出从一到N之间的所有素数。

可以一个一个的找:

// find out all the primes from 1 to N

package main

  


import (

"fmt"

"math"

"sync"

)

  


func main() {

var n int

fmt.Scan(&n)

primes := findPrimes(n)

fmt.Println(primes)

}

  


func findPrimes(n int) []int {

primes := make([]int, 0)

for i := 2; i <= n; i++ {

isPrime := true

for j := 2; j <= int(math.Sqrt(float64(i))); j++ {

if i%j == 0 {

isPrime = false

break

}

}

if isPrime {

primes = append(primes, i)

}

}

return primes

}

并行的方式

这个方式在多核上的效率更高。

// find out all the primes from 1 to N

package main

import (
    "fmt"
    "math"
    "sync"
)

func main() {
    var n int
    fmt.Scan(&n)
    primes := findPrimes2(n)
    fmt.Println(primes)
}

// use channel to parallel the process
func findPrimes2(n int) []int {
    primes := make([]int, 0)
    res := make(chan int, 10) // channel to receive the prime number
    go primeWorker(n, res)
    for prime := range res {
        primes = append(primes, prime)
    }
    return primes
}

func primeWorker(n int, res chan int) {
    // use a buffered channel to run the goroutine in parallel
    ch := make(chan int, 10)
    go func() {
        for i := 2; i <= n; i++ {
            // send the prime number to channel
            ch <- i
        }
        close(ch) // close the channel
    }()

    // get the prime number from channel and start a goroutine to check if it is prime
    var wg sync.WaitGroup
    for i := range ch {
        wg.Add(1)
        go func(i int) {

            fmt.Println("checking", i, "is prime or not")

            defer wg.Done()

            if isPrime(i) {

            res <- i // send the prime number to channel

            }
        }(i)
    }
    go func() {
        wg.Wait()
        close(res)
    }()
}

func isPrime(n int) bool {
    isPrime := true
    for j := 2; j <= int(math.Sqrt(float64(n))); j++ {
        if n%j == 0 {
            isPrime = false
            break
        }
    }
    return isPrime
}