如何解决通道关闭后如何关闭 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())
用这个你可以创建一个 context
和 cancel
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 举报,一经查实,本站将立刻删除。