发布时间:2024-12-22 21:48:26
以一个简单的例子来说明如何使用WaitGroup进行线程等待:
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
// 模拟耗时操作
for i := 0; i < 1000000000; i++ {
}
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers done")
}
在上面的代码中,我们首先创建了一个WaitGroup对象wg。然后使用for循环创建了5个worker协程,并分别给每个协程传递了WaitGroup对象的指针。
在worker函数中,我们使用defer关键字在函数执行完毕时调用了WaitGroup的Done方法,用于减少计数。在最后,我们调用了WaitGroup的Wait方法,用于等待所有协程执行完毕。
通过运行上述代码,我们可以看到输出结果中首先打印了各个协程的启动信息,然后等待所有协程执行完毕后打印了"All workers done"。
package main
import (
"fmt"
"time"
)
func worker(id int, done chan bool) {
fmt.Printf("Worker %d starting\n", id)
// 模拟耗时操作
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
// 发送信号告诉主协程我已经执行完毕了
done <- true
}
func main() {
numWorkers := 5
done := make(chan bool)
for i := 1; i <= numWorkers; i++ {
go worker(i, done)
}
// 等待所有子协程执行完毕
for i := 0; i < numWorkers; i++ {
<-done
}
fmt.Println("All workers done")
}
在上述代码中,我们首先创建了一个用于接收子协程完成信号的通道done。然后使用for循环创建了5个worker协程,并分别给每个协程传递了done通道。
在worker函数中,我们在任务执行完毕后向done通道发送一个信号,告诉主协程任务已经完成。主协程通过<-done语法从通道中接收信号,并等待所有子协程都完成后输出"All workers done"。
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context, id int) {
fmt.Printf("Worker %d starting\n", id)
// 模拟耗时操作
time.Sleep(time.Second)
select {
case <-ctx.Done():
fmt.Printf("Worker %d done (canceled)\n", id)
default:
fmt.Printf("Worker %d done\n", id)
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numWorkers := 5
for i := 1; i <= numWorkers; i++ {
go worker(ctx, i)
}
time.Sleep(3 * time.Second)
cancel()
time.Sleep(time.Second)
}
在上述代码中,我们首先使用context.WithCancel创建了一个Context对象ctx和一个用于取消任务的cancel函数。然后使用for循环创建了5个worker协程,并分别给每个协程传递了ctx。
在worker函数中,我们使用select语句监听ctx的状态,如果收到了取消信号,则打印"Worker %d done (canceled)",否则打印"Worker %d done"。
主协程在执行完所有子协程之后,通过调用cancel函数向子协程发送取消信号。这样,所有的子协程都会接收到取消信号并结束自己的任务。
通过以上三种方法,Golang提供了多样化的线程等待机制,开发者可以根据具体需求选择最适合的方法。同时,在实际开发中,我们还可以根据具体场景结合使用WaitGroup、Channel和Context等进行线程的等待操作。这样既能保证并发任务的正确执行,又能实现更好的任务控制和管理。这就是Golang线程等待的相关知识,请大家多多练习和实践。