4

SHA1 をカウントし、2 つのゼロで始まるものを出力する golang のプログラムがあります。ゴルーチンとチャネルを使用したい。私の問題は、生成される結果の数がわからない場合、select 句を適切に終了する方法がわからないことです。

多くのチュートリアルはそれを事前に知っており、カウンターがヒットすると終了します。他の人は WaitGroups を使用することを提案していますが、私はそうしたくありません。結果がチャネルに表示されたらすぐにメイン スレッドに出力したいのです。ゴルーチンが終了したらチャネルを閉じることを提案する人もいますが、非同期の終了後にチャネルを閉じたいので、方法がわかりません。

私の要件を達成するのを手伝ってください:

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 に答える 2

2

プログラムの構造を再検討する必要があります。これは、あなたが探していると私が推測するものの実用的な例です。Go プレイグラウンドで実行できます

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
}

編集:これはハッシュ計算ごとに個別のルーチンを起動しませんが、正直なところ、そうすることの価値がわかりません。これらすべてのルーチンをスケジューリングすると、単一のルーチンでコードを実行するよりもはるかに多くのコストがかかる可能性があります。必要に応じて、N 個のルーチンのチャンクに分割できますが、1:1 のマッピングはこれには適していません。

于 2014-02-14T16:07:36.853 に答える