How to break out of favorites in golang

I have a program in golang that counts SHA1 and prints those starting with two zeros. I want to use goroutines and feeds. My problem is that I don’t know how to gracefully exit the select clause if I don’t know how many results it will produce.

Many textbooks know that in advance and go out when the counter is found. Others suggest using WaitGroups, but I do not want to do this: I want to print the results in the main stream as soon as it appears in the channel. Some suggest closing the channel when the goroutines are finished, but I want to close it after asynchronous completion, so I don’t know how to do it.

Please help me achieve my requirements:

package main

import (
    "crypto/sha1"
    "fmt"
    "time"
    "runtime"
    "math/rand"
)

type Hash struct {
    message string
    hash [sha1.Size]byte

}

var counter int = 0
var max int = 100000
var channel = make(chan Hash)
var source = rand.NewSource(time.Now().UnixNano())
var generator = rand.New(source)

func main() {
    nCPU := runtime.NumCPU()
    runtime.GOMAXPROCS(nCPU)
    fmt.Println("Number of CPUs: ", nCPU)
    start := time.Now()

    for i := 0 ; i < max ; i++ {
        go func(j int) {
            count(j)
        }(i)
    }
    // close channel here? I can't because asynchronous producers work now

    for {
        select {
                    // how to stop receiving if there are no producers left?
            case hash := <- channel:
                fmt.Printf("Hash is %v\n ", hash)
            }
    }
    fmt.Printf("Count of %v sha1 took %v\n", max, time.Since(start))
}

func count(i int) {
    random := fmt.Sprintf("This is a test %v", generator.Int())
    hash := sha1.Sum([]byte(random))

    if (hash[0] == 0 && hash[1] == 0) {
        channel <- Hash{random, hash}
    }
}
+4
2

-: , , ? , , . , , .

-. . ( ):

func producer(max int, out chan<- Hash, wg *sync.WaitGroup) {
    defer wg.Done()

    for i := 0; i < max; i++ {
        random := fmt.Sprintf("This is a test %v", rand.Int())
        hash := sha1.Sum([]byte(random))

        if hash[0] == 0 && hash[1] == 0 {
            out <- Hash{random, hash}
        }
    }

    close(out)
}

, , , . , .

func consumer(max int, in <-chan Hash, wg *sync.WaitGroup) {
    defer wg.Done()

    for {
        hash, ok := <-in

        if !ok {
            break
        }

        fmt.Printf("Hash is %v\n ", hash)
    }
}

in , (ok). , . .

, :

wg := &sync.WaitGroup{}
c := make(chan Hash)

wg.Add(1)
go producer(max, c, wg)

wg.Add(1)
go consumer(max, c, wg)

wg.Wait()

WaitGroup , , , wg.Done goroutines.

Sidenote

, Rand, , . math/rand. :

rand.Seed(time.Now().UnixNano())
rand.Int()
+2

, , . , , .

package main

import (
    "crypto/sha1"
    "fmt"
    "math/rand"
    "runtime"
    "time"
)

type Hash struct {
    message string
    hash    [sha1.Size]byte
}

const Max int = 100000

func main() {
    nCPU := runtime.NumCPU()
    runtime.GOMAXPROCS(nCPU)

    fmt.Println("Number of CPUs: ", nCPU)

    hashes := Generate()
    start := time.Now()

    for hash := range hashes {
        fmt.Printf("Hash is %v\n ", hash)
    }

    fmt.Printf("Count of %v sha1 took %v\n", Max, time.Since(start))
}

func Generate() <-chan Hash {
    c := make(chan Hash, 1)

    go func() {
        defer close(c)

        source := rand.NewSource(time.Now().UnixNano())
        generator := rand.New(source)

        for i := 0; i < Max; i++ {
            random := fmt.Sprintf("This is a test %v", generator.Int())
            hash := sha1.Sum([]byte(random))

            if hash[0] == 0 && hash[1] == 0 {
                c <- Hash{random, hash}
            }
        }
    }()

    return c
}

: Hash, , , . , , , . , N , 1:1 .

+2

Source: https://habr.com/ru/post/1526971/


All Articles