MST

星途 面试题库

面试题:Go中如何在复杂并发场景下精确控制超时与资源回收

在一个具有多层嵌套的并发结构中,每个内层协程又有子协程,并且存在共享资源。现在要求在整体操作超时时,能够精确地回收所有资源,避免资源泄漏。请详细阐述实现方案,包括使用到的Go语言特性、数据结构和控制逻辑。
25.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 使用到的Go语言特性
    • Context(上下文):Go语言的context包用于在多个goroutine之间传递截止时间、取消信号等信息。通过context可以方便地实现超时控制以及在超时时取消所有相关的goroutine。例如,可以使用context.WithTimeout函数创建一个带有超时时间的context
    • WaitGroup:用于等待一组goroutine完成。在并发操作中,我们可以使用WaitGroup来确保所有的协程都执行完毕后再进行资源回收等后续操作。例如,在启动每个协程前调用wg.Add(1),在协程结束时调用wg.Done(),最后使用wg.Wait()等待所有协程结束。
    • Mutex(互斥锁):由于存在共享资源,为了避免竞态条件,需要使用Mutex来保护共享资源。在访问共享资源前加锁(mu.Lock()),访问结束后解锁(mu.Unlock())。
  2. 数据结构
    • Map(映射):可以用来管理共享资源,例如,将共享资源的标识符作为键,资源对象作为值存储在map中。在Go语言中,标准库的map不是线程安全的,所以在并发访问时需要结合Mutex来使用。
    • Channel(通道):用于在不同的goroutine之间传递数据和信号。例如,可以使用一个无缓冲通道来通知子协程需要取消操作。
  3. 控制逻辑
    • 创建顶层上下文
      ctx, cancel := context.WithTimeout(context.Background(), timeoutDuration)
      defer cancel()
      
      这里timeoutDuration是设定的超时时间。
    • 管理协程
      • 启动每个外层协程时,传递上下文ctx。例如:
      var wg sync.WaitGroup
      for _, task := range outerTasks {
          wg.Add(1)
          go func(ctx context.Context, task Task) {
              defer wg.Done()
              // 内层协程管理
              var innerWg sync.WaitGroup
              for _, innerTask := range task.InnerTasks {
                  innerWg.Add(1)
                  go func(ctx context.Context, innerTask InnerTask) {
                      defer innerWg.Done()
                      // 子协程管理
                      var subWg sync.WaitGroup
                      for _, subTask := range innerTask.SubTasks {
                          subWg.Add(1)
                          go func(ctx context.Context, subTask SubTask) {
                              defer subWg.Done()
                              select {
                              case <-ctx.Done():
                                  // 超时时清理子协程资源
                                  return
                              default:
                                  // 执行子协程任务
                                  subTask.Execute()
                              }
                          }(ctx, subTask)
                      }
                      subWg.Wait()
                      select {
                      case <-ctx.Done():
                          // 超时时清理内层协程资源
                          return
                      default:
                          // 执行内层协程任务
                          innerTask.Execute()
                      }
                  }(ctx, innerTask)
              }
              innerWg.Wait()
              select {
              case <-ctx.Done():
                  // 超时时清理外层协程资源
                  return
              default:
                  // 执行外层协程任务
                  task.Execute()
              }
          }(ctx, task)
      }
      wg.Wait()
      
    • 资源回收
      • 在每个协程内部,通过select语句监听ctx.Done()信号。一旦接收到取消信号,立即执行资源清理操作。例如,如果共享资源是文件描述符,关闭文件描述符;如果是网络连接,关闭网络连接等。
      • 对于共享资源的清理,在清理前需要加锁,确保在并发环境下不会出现问题。例如:
      mu.Lock()
      // 清理共享资源
      delete(sharedResourceMap, resourceID)
      mu.Unlock()
      

通过上述方案,利用Go语言的contextWaitGroupMutex等特性,结合合适的数据结构和控制逻辑,可以在整体操作超时时精确地回收所有资源,避免资源泄漏。