微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

通道关闭后如何关闭 goroutine

如何解决通道关闭后如何关闭 goroutine

我正在尝试编写一个程序来同时挖掘一个比特币。我已经设置好每个 goroutine 都有一个初始起始随机数,每个随机数都是 4 的一小部分,即。 2**64 - 1(uint64 类型的最大数量)/1 或 2 或 3 或 4。

这些矿工中只有一个会遇到正确的随机数,当发生这种情况时,我希望它通过渠道将其传递给矿工经理,当发生这种情况时,我希望其他 3 名矿工停止他们正在做的事情.

唯一的问题是我不知道如何销毁正在运行的 goroutine,或者是否有办法完成我的要求。

func miner(blockNumber int,transactions string,prevIoUsHash string,zeroPrefix string,startNonce uint64,nonceChan chan uint64,hashChan chan string) {
    var text string
    var newHash string

    for {
        text = strconv.Itoa(blockNumber) + transactions + prevIoUsHash + strconv.FormatUint(startNonce,10)
        newHash = encrypt(text)

        if startswith(newHash,zeroPrefix) {
            nonceChan <- startNonce
            hashChan  <- newHash

            close(nonceChan)
            close(hashChan)
            break
        } else {
            startNonce++
        }
    }
}

func mine(blockNumber int,zeroPrefix int) Block {
    var prefixString string
    var newHash string
    var nonce uint64
    var startNonce uint64

    nonceChan := make(chan uint64)
    hashChan := make(chan string)

    for i := 0; i < zeroPrefix; i++ {
        prefixString += "0"
    }

    start := time.Now()

    for i := 0; i < 4; i++{
        // This line is for deciding at what nonce value a miner should start at.
        startNonce = uint64((float64(i) / 4) * math.Pow(2,64))

        go func() {
            fmt.Println("Started miner with start nonce of",startNonce)
            miner(blockNumber,transactions,prevIoUsHash,prefixString,startNonce,nonceChan,hashChan)
        }()
    }

    nonce = <- nonceChan
    newHash = <- hashChan

    // Here is where I would like to destroy the other three miners

    block := Block{
        blockNumber,newHash,nonce,zeroPrefix,time.Since(start),}

    return block
}

解决方法

在启动所有 goroutines 的函数中创建一个 ctx,cancel := context.WithCancel(context.Background()) 并将其传递给所有 goroutines(作为函数中的第一个参数)。

当工作应该取消时,调用 cancel 函数。你可以这样做,例如收到结果后在 main 函数中。

在每个 goroutine 中检查 for 的选择(在您的 ctx.Done 循环中):

select {
case <-ctx.Done():
    return
default:
}

// continue mining

示例:

func miner(ctx context.Context,...) {
    defer func() {
        // any necessary cleanup
    }

    for {
        select {
        case <-ctx.Done():
            // abort was called for: exit
            return
        default:
        }

        // continue mining
    }
}
func mine() {
    // use a single channel to get the result. You could 
    // block yourself if you use multiple channels
    chResult := make(chan result)

    // create context
    ctx,cancel := context.WithCancel(context.Background())

    for i := 0; i < 4; i++{
        // ...

        // pass the context into the miner
        go miner(ctx,chResult,...)
    }

    // block for first miner to be successful
    res := <-chResult
   
    // cancel the other routines
    cancel()
    
    // ...
}

result 可以是:

struct result {
    hash  string
    nonce uint64
}
,

您可以使用 context,它是处理 goroutine 终止的典型对象之一。

context : 包上下文定义了上下文类型,它携带截止日期、取消信号和其他跨 API 边界和进程之间的请求范围值。

ctx,cancel := context.WithCancel(context.Background()) 用这个你可以创建一个 contextcancel func。

只需在您的 go 例程中传递 ctx and cancel,当您在任何 go 例程中完成时,只需进行 cancel() func() 调用。然后 ctx.done() 为真,然后 switch 的第一种情况为真,它将从您的所有 go 例程中返回。


func miner( ctx context.Context,blockNumber int,transactions string,previousHash string,zeroPrefix string,startNonce uint64,nonceChan chan uint64,hashChan chan string) {
    var text string
    var newHash string

    for {
        select {
        case <-ctx.Done():  // if cancel() execute
           return
        default:
            text = strconv.Itoa(blockNumber) + transactions + previousHash + strconv.FormatUint(startNonce,10)
            newHash = encrypt(text)

            if startswith(newHash,zeroPrefix) {
                nonceChan <- startNonce
                hashChan  <- newHash

                close(nonceChan)
                close(hashChan)
                break
            } else {
                startNonce++
            }

        }

    }
}

func mine(blockNumber int,zeroPrefix int) Block {
    var prefixString string
    var newHash string
    var nonce uint64
    var startNonce uint64

    nonceChan := make(chan uint64)
    hashChan := make(chan string)

    for i := 0; i < zeroPrefix; i++ {
        prefixString += "0"
    }

    start := time.Now()
    ctx,cancel := context.WithCancel(context.Background())

    for i := 0; i < 4; i++{
        // This line is for deciding at what nonce value a miner should start at.
        startNonce = uint64((float64(i) / 4) * math.Pow(2,64))

        go func(ctx context.Context) {
            fmt.Println("Started miner with start nonce of",startNonce)
            miner(ctx,blockNumber,transactions,previousHash,prefixString,startNonce,nonceChan,hashChan)
        }(ctx)
    }

    nonce = <- nonceChan
    newHash = <- hashChan
    cancel()

    // Here is where I would like to destroy the other three miners

    block := Block{
        blockNumber,newHash,nonce,zeroPrefix,time.Since(start),}

    return block
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。