複数のgoroutineでgocsv.Marshalによる競合を防ぐ
var gocsvMutex sync.Mutex // グローバルスコープで gocsv の操作を保護するためのミューテックス func (c *CSVProcessor[T]) MarshalWithWriteHeader(w io.Writer, csvData interface{}, charset string, writeHeader bool) error { // エラーを捕捉するためのチャネル errChan := make(chan error, 1) go func() { if c.translator.CurrentLocale() != model.LocaleJa { cleanup := c.SetUpTranslatedHeaderNormalizer() defer cleanup() } gocsvMutex.Lock() // gocsv のスレッドセーフを保証 defer gocsvMutex.Unlock() var err error if writeHeader { err = gocsv.Marshal(csvData, encoding.NewWriter(w, charset)) } else { // BOMは最初だけ必要なので、途中からはBOMなしにする if charset == "UTF-8_BOM" { charset = "UTF-8" } err = gocsv.MarshalWithoutHeaders(csvData, encoding.NewWriter(w, charset)) } // エラーがあればチャネルで通知 if err != nil { errChan <- err return } close(errChan) // エラーがなければチャネルを閉じる }() // ゴルーチン内でのエラーを受け取る if err := <-errChan; err != nil { return err } return nil }