我的任务是编写一个日志解析器。路径切片作为路径传递,我想创建每行结构的切片。我想逐行阅读,以免占用大量内存。
一切正常,但有时有些数据来不及写入,因此会发生数据泄漏。我该如何解决这个问题?
func test(matches string) (*domain.NGINX, error) {
var wg sync.WaitGroup
logChan := make(chan *domain.NGINX)
errChan := make(chan error)
var logs []*domain.NGINX
go func() {
for log := range logChan {
logs = append(logs, log)
}
}()
for _, match := range matches {
wg.Add(1)
go func(filePath string) {
defer wg.Done()
file, err := os.Open(filePath)
if err != nil {
errChan <- fmt.Errorf("accessing path: %v", err)
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
logNGINX, err := ParseLogLineToNGINXObject(line)
if err != nil {
continue
}
logChan <- logNGINX
}
if err := scanner.Err(); err != nil {
errChan <- fmt.Errorf("scanning file: %v", err)
return
}
}(match)
}
wg.Wait()
close(logChan)
close(errChan)
var err error
for e := range errChan {
fmt.Printf("Error: %v\n", e)
err = e
}
return logs, err
}
正如评论中提到的,写入
errChan
的错误是阻塞的,所以你的 goroutine 会卡在那里。因此,WaitGroup 锁不会被释放,并且你的主 goroutine 会卡在 Wait() 处。
如果您希望在发生错误时使所有读数失败,请尝试
golang.org/x/sync/errgroup
。或者,如果您只想失败一些,请创建一个与 matches
长度相同的 []error 切片,并将错误写入从 for 循环获得的索引处。这并不活泼,因为每个 goroutine 都会访问它的内存。稍后您可以使用 errors.Join
来处理错误,它会为您过滤掉 nil
值。