英文:
Better way to exit for loop when using sync.WaitGroup?
问题
在使用sync.WaitGroup时,有没有更好的方法来退出for循环?目前,我使用bool类型的变量e作为触发器,在循环结束时跳出for循环,这个方法是有效的。但是,如果我尝试在检查orders >= quantity的地方跳出for循环,就会出现各种错误。
有没有比我的bool代码更好的方法来跳出这个循环,而不会引发panic错误?
package main
import (
"fmt"
"math/rand"
"strconv"
"sync"
)
func main() {
var wg sync.WaitGroup
var accounts int = 1
var emails int = 1000
for i := 0; i < accounts; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
threads := 500 //同时运行的最大子例程数
var orderMutex sync.Mutex
var quantity = 2
var orders = 0
sem := make(chan bool, threads)
var wgnested sync.WaitGroup
var e = false
for x := 0; x < emails; x++ {
sem <- true //阻塞
orderMutex.Lock()
if orders >= quantity {
fmt.Println(strconv.Itoa(x) + " Quantity Exceeded Stopping")
e = true
}
orderMutex.Unlock()
wgnested.Add(1)
go func() {
defer wgnested.Done()
defer func() { <-sem }()
//模拟订单
if rand.Intn(50) == 7 {
orderMutex.Lock()
orders++
orderMutex.Unlock()
}
fmt.Println(strconv.Itoa(i) + " Made to end ")
}() //func
if e {
break
}
} //x
wgnested.Wait()
loop:
for {
select {
case <-sem:
fmt.Println("quit")
break loop
default:
sem <- true
}
}
fmt.Println(strconv.Itoa(i) + " Orders: " + strconv.Itoa(orders))
}(i)
} //i
wg.Wait()
}
英文:
Is there a better way to exit the for loop when using sync.WaitGroup? At the moment I am using bool e as a trigger to break out of the for loop at the end of the loop, which works. If I try to break the for loop where I check orders >= quantity I get all kinds of errors.
Is there a better way to break this loop than my bool code without causing panic?
package main
import (
"fmt"
"math/rand"
"strconv"
"sync"
)
func main() {
var wg sync.WaitGroup
var accounts int = 1
var emails int = 1000
for i := 0; i < accounts; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
threads := 500 //Max subroutines to run at once
var orderMutex sync.Mutex
var quantity = 2
var orders = 0
sem := make(chan bool, threads)
var wgnested sync.WaitGroup
var e = false
for x := 0; x < emails; x++ {
sem <- true //block
orderMutex.Lock()
if orders >= quantity {
fmt.Println(strconv.Itoa(x) + " Quantity Exceeded Stopping")
e = true
}
orderMutex.Unlock()
wgnested.Add(1)
go func() {
defer wgnested.Done()
defer func() { <-sem }()
//Simulate orders
if rand.Intn(50) == 7 {
orderMutex.Lock()
orders++
orderMutex.Unlock()
}
fmt.Println(strconv.Itoa(i) + " Made to end ")
}() //func
if e {
break
}
} //x
wgnested.Wait()
loop:
for {
select {
case <-sem:
fmt.Println("quit")
break loop
default:
sem <- true
}
}
fmt.Println(strconv.Itoa(i) + " Orders: " + strconv.Itoa(orders))
}(i)
} //i
wg.Wait()
}
答案1
得分: 2
你可以使用context.Context
来在上下文被取消时停止循环。
示例
package main
import (
"context"
"fmt"
"math/rand"
"strconv"
"sync"
)
func main() {
var (
wg sync.WaitGroup
accounts int = 1
emails int = 1000
//
ctx, cancel = context.WithCancel(context.Background()) // 创建新的上下文
)
for i := 0; i < accounts; i++ {
wg.Add(1)
go func(i int) {
// 当goroutine完成时
// 取消上下文
defer func() {
wg.Done()
cancel()
}()
//
var (
// threads = 500 //同时运行的最大子例程数
orderMutex sync.Mutex
quantity = 2
orders = 0
wgnested sync.WaitGroup
)
for x := 0; x < emails; x++ {
select {
// 上下文完成的情况
case <-ctx.Done():
return
default:
// 检查上下文是否被取消
// 退出循环
if ctx.Err() != nil {
return
}
orderMutex.Lock()
if orders >= quantity {
fmt.Println(strconv.Itoa(x) + " 数量超过限制,停止")
cancel() // 发送取消上下文的信号
}
orderMutex.Unlock()
wgnested.Add(1)
go func() {
defer wgnested.Done()
// 模拟订单
if rand.Intn(50) == 7 {
orderMutex.Lock()
orders++
orderMutex.Unlock()
}
fmt.Println(strconv.Itoa(x) + " 到达终点") // 我使用了"x"而不是"i"
}()
wgnested.Wait()
}
}
//
fmt.Println(strconv.Itoa(i) + " 订单数: " + strconv.Itoa(orders))
}(i)
} //i
wg.Wait()
}
输出
0 到达终点
1 到达终点
2 到达终点
3 到达终点
4 到达终点
5 到达终点
6 到达终点
...
...
...
88 到达终点
89 到达终点
90 到达终点
91 到达终点
92 到达终点
93 到达终点
94 数量超过限制,停止
94 到达终点
英文:
you use context.Context
to stop a loop when the context is cancelled.
Example
package main
import (
"context"
"fmt"
"math/rand"
"strconv"
"sync"
)
func main() {
var (
wg sync.WaitGroup
accounts int = 1
emails int = 1000
//
ctx, cancel = context.WithCancel(context.Background()) // create new context
)
for i := 0; i < accounts; i++ {
wg.Add(1)
go func(i int) {
// when goroutine finish
// cancel the context
defer func() {
wg.Done()
cancel()
}()
//
var (
// threads = 500 //Max subroutines to run at once
orderMutex sync.Mutex
quantity = 2
orders = 0
wgnested sync.WaitGroup
)
for x := 0; x < emails; x++ {
select {
// case context is done.
case <-ctx.Done():
return
default:
// check context is cancelled
// exit for loop
if ctx.Err() != nil {
return
}
orderMutex.Lock()
if orders >= quantity {
fmt.Println(strconv.Itoa(x) + " Quantity Exceeded Stopping")
cancel() // signal cancel context
}
orderMutex.Unlock()
wgnested.Add(1)
go func() {
defer wgnested.Done()
//Simulate orders
if rand.Intn(50) == 7 {
orderMutex.Lock()
orders++
orderMutex.Unlock()
}
fmt.Println(strconv.Itoa(x) + " Made to end ") // i used "x" instead of "i"
}()
wgnested.Wait()
}
}
//
fmt.Println(strconv.Itoa(i) + " Orders: " + strconv.Itoa(orders))
}(i)
} //i
wg.Wait()
}
Output
0 Made to end
1 Made to end
2 Made to end
3 Made to end
4 Made to end
5 Made to end
6 Made to end
...
...
...
88 Made to end
89 Made to end
90 Made to end
91 Made to end
92 Made to end
93 Made to end
94 Quantity Exceeded Stopping
94 Made to end
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论