面试题答案
一键面试实现思路
- 创建context:使用
context.WithCancel
或context.WithTimeout
创建一个上下文对象,用于控制并发任务的生命周期。context.WithCancel
可以手动取消任务,context.WithTimeout
则在指定时间后自动取消任务。 - 启动并发任务:在
go
协程中执行任务,每个任务接收创建的上下文对象作为参数。在任务执行过程中,定期检查上下文的取消信号,如通过ctx.Done()
通道是否关闭来判断。 - 共享资源管理:将共享资源(如数据库连接)封装在一个结构体中,并提供获取和释放资源的方法。在任务开始时获取资源,在任务结束(无论正常结束还是因取消或超时结束)时释放资源。
核心代码片段
package main
import (
"context"
"fmt"
"sync"
"time"
)
// Resource 模拟共享资源
type Resource struct {
// 这里可以是数据库连接等实际资源
Data string
}
// ResourceManager 资源管理器
type ResourceManager struct {
resources sync.Map
}
// GetResource 获取资源
func (rm *ResourceManager) GetResource(key string) *Resource {
res, ok := rm.resources.Load(key)
if ok {
return res.(*Resource)
}
newRes := &Resource{Data: "new resource for " + key}
rm.resources.Store(key, newRes)
return newRes
}
// ReleaseResource 释放资源
func (rm *ResourceManager) ReleaseResource(key string) {
rm.resources.Delete(key)
}
func task(ctx context.Context, key string, rm *ResourceManager) {
res := rm.GetResource(key)
defer rm.ReleaseResource(key)
for {
select {
case <-ctx.Done():
fmt.Printf("Task %s cancelled, releasing resource\n", key)
return
default:
fmt.Printf("Task %s is working with resource: %v\n", key, res)
time.Sleep(1 * time.Second)
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var rm ResourceManager
var wg sync.WaitGroup
wg.Add(2)
go func() {
task(ctx, "task1", &rm)
wg.Done()
}()
go func() {
task(ctx, "task2", &rm)
wg.Done()
}()
wg.Wait()
fmt.Println("All tasks completed")
}
在上述代码中:
Resource
结构体模拟共享资源,ResourceManager
结构体管理这些资源。task
函数是具体的并发任务,接收上下文和资源管理器作为参数。任务中获取资源,通过ctx.Done()
通道监听取消信号,在任务结束时释放资源。main
函数中创建了一个带超时的上下文,启动两个并发任务,并等待它们完成。