通道关闭后如何关闭 goroutines
How to close goroutines after channel has been shut
我正在尝试编写一个同时挖掘比特币区块的程序。我已经设置好它,以便每个 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, transactions string, previousHash string, 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,
transactions,
previousHash,
newHash,
nonce,
zeroPrefix,
time.Since(start),
}
return block
}
在启动所有goroutines的函数中创建一个ctx, cancel := context.WithCancel(context.Background())
并将其传递给所有goroutines(作为函数中的第一个参数)。
当需要取消工作时,调用cancel
函数。你可以这样做,例如在收到结果后的 main
函数中。
在每个 goroutine 中使用 select(在你的 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
这是处理 go 例程终止的典型对象之一。
context :
包上下文定义了上下文类型,它携带截止日期、取消信号和跨 API 边界和进程之间的其他请求范围的值。
ctx, cancel := context.WithCancel(context.Background())
用这个你可以创建一个 context
和 cancel
函数。
只需在您的 go 例程中传递 ctx and cancel
,当您在任何 go 例程中完成后,只需进行 cancel()
func()
调用。然后 ctx.done()
将为真,然后 switch 的第一个 case 将为真,它将 return 来自你所有的 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, transactions string, previousHash string, 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,
transactions,
previousHash,
newHash,
nonce,
zeroPrefix,
time.Since(start),
}
return block
}
我正在尝试编写一个同时挖掘比特币区块的程序。我已经设置好它,以便每个 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, transactions string, previousHash string, 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,
transactions,
previousHash,
newHash,
nonce,
zeroPrefix,
time.Since(start),
}
return block
}
在启动所有goroutines的函数中创建一个ctx, cancel := context.WithCancel(context.Background())
并将其传递给所有goroutines(作为函数中的第一个参数)。
当需要取消工作时,调用cancel
函数。你可以这样做,例如在收到结果后的 main
函数中。
在每个 goroutine 中使用 select(在你的 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
这是处理 go 例程终止的典型对象之一。
context :
包上下文定义了上下文类型,它携带截止日期、取消信号和跨 API 边界和进程之间的其他请求范围的值。
ctx, cancel := context.WithCancel(context.Background())
用这个你可以创建一个 context
和 cancel
函数。
只需在您的 go 例程中传递 ctx and cancel
,当您在任何 go 例程中完成后,只需进行 cancel()
func()
调用。然后 ctx.done()
将为真,然后 switch 的第一个 case 将为真,它将 return 来自你所有的 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, transactions string, previousHash string, 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,
transactions,
previousHash,
newHash,
nonce,
zeroPrefix,
time.Since(start),
}
return block
}