MST

星途 面试题库

面试题:Go每个请求一个goroutine下的文件资源管理

假设在Go的Web应用里,每个请求对应的goroutine可能需要读取或写入文件。请详细阐述如何在并发环境下安全且高效地管理文件资源,比如如何避免文件描述符耗尽,如何处理文件读写的并发冲突,以及如何优雅地关闭文件资源,同时结合sync包和context包的知识来设计一个示例代码片段。
19.0万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

避免文件描述符耗尽

  1. 限制并发数:使用 sync.WaitGroup 和一个通道来限制同时打开文件的 goroutine 数量。通道的缓冲区大小决定了允许同时打开文件的最大数量。
  2. 及时关闭文件:在使用完文件后,立即调用 file.Close() 方法关闭文件,释放文件描述符。

处理文件读写的并发冲突

  1. 互斥锁:使用 sync.Mutex 来保护对文件的读写操作。在进行读写之前锁定互斥锁,操作完成后解锁。
  2. 读写锁:如果读操作远多于写操作,可以使用 sync.RWMutex。读操作使用读锁(RLock),写操作使用写锁(Lock)。

优雅地关闭文件资源

  1. defer 关键字:在打开文件后,使用 defer file.Close() 确保在函数返回时文件会被关闭,即使发生错误。
  2. context 包:结合 context.Context,在取消上下文时,及时关闭文件并清理资源。

示例代码

package main

import (
    "context"
    "fmt"
    "io/ioutil"
    "log"
    "sync"
)

var (
    fileMutex sync.Mutex
    fileLimit = make(chan struct{}, 10) // 限制同时打开10个文件
)

func readFile(ctx context.Context, filePath string) {
    // 获取文件打开许可
    fileLimit <- struct{}{}
    defer func() { <-fileLimit }()

    fileMutex.Lock()
    data, err := ioutil.ReadFile(filePath)
    fileMutex.Unlock()
    if err != nil {
        log.Printf("Error reading file %s: %v", filePath, err)
        return
    }

    select {
    case <-ctx.Done():
        log.Printf("Operation cancelled for file %s", filePath)
        return
    default:
        fmt.Printf("Read data from %s: %s\n", filePath, data)
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    var wg sync.WaitGroup

    filePaths := []string{"file1.txt", "file2.txt", "file3.txt"}
    for _, filePath := range filePaths {
        wg.Add(1)
        go func(fp string) {
            defer wg.Done()
            readFile(ctx, fp)
        }(filePath)
    }

    // 模拟一段时间后取消操作
    go func() {
        select {
        case <-ctx.Done():
        case <-time.After(2 * time.Second):
            cancel()
        }
    }()

    wg.Wait()
}

在这个示例中:

  1. fileLimit 通道用于限制同时打开文件的数量,避免文件描述符耗尽。
  2. fileMutex 互斥锁用于保护文件读取操作,防止并发冲突。
  3. context.Context 用于在需要时优雅地取消操作,并通过 select 语句检查上下文是否已取消,以决定是否继续执行文件读取操作。
  4. defer 关键字确保文件在使用后被关闭(ioutil.ReadFile 内部会自动处理文件关闭),同时 defer 也用于释放 fileLimit 通道的许可。