面试题答案
一键面试- 实现思路:
- 在主函数中创建一个
context.Context
和context.CancelFunc
,通过context.WithCancel
方法。 - 将
context.Context
传递给主goroutine
。 - 主
goroutine
在启动子goroutine
时,将context.Context
传递下去。同样,子goroutine
在启动孙goroutine
时也传递context.Context
。 - 每个
goroutine
内部通过监听context.Context
的取消信号来决定是否退出。 - 在取消信号发出后,每个
goroutine
要负责清理自己所占用的资源。
- 在主函数中创建一个
- 核心代码片段:
package main
import (
"context"
"fmt"
"sync"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
wg.Add(1)
go mainGoroutine(ctx, &wg)
// 模拟一段时间后发出取消信号
time.Sleep(2 * time.Second)
cancel()
wg.Wait()
}
func mainGoroutine(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
var subWg sync.WaitGroup
for i := 0; i < 3; i++ {
subWg.Add(1)
go subGoroutine(ctx, &subWg, i)
}
subWg.Wait()
}
func subGoroutine(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
var grandChildWg sync.WaitGroup
for i := 0; i < 2; i++ {
grandChildWg.Add(1)
go grandChildGoroutine(ctx, &grandChildWg, i)
}
grandChildWg.Wait()
}
func grandChildGoroutine(ctx context.Context, wg *sync.WaitGroup, id int) {
defer wg.Done()
for {
select {
case <-ctx.Done():
// 清理资源
fmt.Printf("Grand - child goroutine %d cleaning up and exiting\n", id)
return
default:
// 模拟工作
fmt.Printf("Grand - child goroutine %d working\n", id)
time.Sleep(200 * time.Millisecond)
}
}
}
在上述代码中:
main
函数创建了一个可取消的context
并传递给mainGoroutine
。mainGoroutine
启动多个subGoroutine
并传递context
。subGoroutine
启动多个grandChildGoroutine
并传递context
。- 每个
goroutine
内部通过select
监听ctx.Done()
信号,在接收到取消信号后进行资源清理并退出。