如何停止Golang中的goroutines?
如何停止Golang中的goroutines? 你好
我需要在循环中调用 goroutine/线程。由于是循环,会有许多 goroutine 并行执行。如果任何一个 routine/线程执行成功,我就需要停止所有其他线程/routine。
有什么方法可以实现这个吗?
5 回复
循环执行有限的次数,并且 goroutine 会进行 API 调用。
如果有任何 goroutine 成功执行,即 API 成功返回,我必须停止所有其他 goroutine 的执行。
更多关于如何停止Golang中的goroutines?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
根据你的 goroutine 正在执行的任务,有几种实现方式——请记住,goroutine 不能像 Unix 进程那样被“杀死”。必须以某种方式通知它停止。你能描述一下你的 goroutine 将要做什么吗?进行 API 调用?运行长时间的计算?运行一个无限(或非常大)的循环?还是其他什么?
使用 context 是正确的做法:
func doCalls() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
wg := sync.WaitGroup{}
for _ := range numGoRoutines {
wg.Add(1)
go func() {
defer cancel()
defer wg.Done()
client := http.Client{}
client.Do(ctx, ...)
}()
}
wg.Wait()
}
@maroux,Go 协程只执行最后一个索引。 即 numGoRoutines 为 4 时,只执行最后一个索引(3)。
func apiCalls(ctx context) {
client := http.Client{}
client.Do(ctx, …)
}
func doCalls() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
wg := sync.WaitGroup{}
for _ := range numGoRoutines {
wg.Add(1)
go func() {
defer cancel()
defer wg.Done()
apiCalls() //–
}()
}
wg.Wait()
}
在Golang中,你可以使用context包和sync.WaitGroup结合通道来实现这个需求。下面是一个示例:
package main
import (
"context"
"fmt"
"sync"
"time"
)
func worker(ctx context.Context, id int, wg *sync.WaitGroup, success chan<- int) {
defer wg.Done()
select {
case <-ctx.Done():
fmt.Printf("Worker %d cancelled\n", id)
return
default:
// 模拟工作
time.Sleep(time.Duration(id) * time.Second)
// 如果工作成功完成
fmt.Printf("Worker %d succeeded\n", id)
select {
case success <- id:
default:
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
success := make(chan int, 1)
// 启动多个goroutine
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(ctx, i, &wg, success)
}
// 等待第一个成功的goroutine
firstSuccess := <-success
fmt.Printf("Worker %d succeeded first, cancelling others\n", firstSuccess)
// 取消所有其他goroutine
cancel()
// 等待所有goroutine完成
wg.Wait()
close(success)
}
另一个更简洁的版本使用errgroup:
package main
import (
"context"
"fmt"
"time"
"golang.org/x/sync/errgroup"
)
func worker(ctx context.Context, id int) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
time.Sleep(time.Duration(id) * time.Second)
fmt.Printf("Worker %d succeeded\n", id)
return nil
}
}
func main() {
g, ctx := errgroup.WithContext(context.Background())
for i := 1; i <= 5; i++ {
id := i
g.Go(func() error {
return worker(ctx, id)
})
}
if err := g.Wait(); err != nil {
fmt.Println("First success completed, others cancelled")
}
}
注意:第二个示例需要安装golang.org/x/sync/errgroup包。

