gpt4 book ai didi

go - 如何在golang中优雅地跳出select

转载 作者:IT王子 更新时间:2023-10-29 00:44:19 24 4
gpt4 key购买 nike

我在 golang 中有一个程序可以计算 SHA1 并打印以两个零开头的 SHA1。我想使用 goroutines 和 channel 。我的问题是,如果我不知道它会产生多少结果,我不知道如何优雅地退出 select 子句。

很多教程都提前知道了,计数器命中就退出。其他人建议使用 WaitGroups,但我不想这样做:我想在主线程出现在 channel 中时立即在主线程中打印结果。有人建议在 goroutines 完成时关闭 channel ,但我想在异步完成后关闭它,所以我不知道如何。

请帮助我实现我的要求:

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}
}
}

最佳答案

首先:如果不知道您的计算何时结束,您甚至如何建模?确保您确切知道您的程序何时以及在何种情况下终止。如果你完成了,你就会知道如何用代码编写它。

您基本上是在处理生产者-消费者问题。一个标准案例。我会建模这样 ( on play ):

制作人

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)
}

显然,您是在暴力破解哈希,因此当循环结束时就到达了终点。我们可以在这里关闭 channel 并向其他 goroutines 发出信号,告诉它们没有什么可以监听了。

消费者

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 channel 获取所有传入消息并检查它是否已关闭(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 的目的是等待生成的 goroutines 完成,由在 goroutines 中调用 wg.Done

旁注

另请注意,您使用的 Rand 对于并发访问而言并不安全。使用初始化的全局在 math/rand 中。示例:

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

关于go - 如何在golang中优雅地跳出select,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21783333/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com