กระรอกดินต้นฉบับกำลังย้ายแถวข้อมูลจากถาดอ่านซ้ำไปยังกล่องเก็บถาวร

Go CSV ReuseRecord: อ่านไวขึ้นโดยไม่เก็บ slice ที่ถูกใช้ซ้ำ

พี่โชว์Engineering

อ่านไฟล์ CSV หลายล้านแถวแล้วเก็บทุกแถวไว้ใน slice อาจทำให้ allocation โตโดยไม่จำเป็นครับ csv.Reader.ReuseRecord บอก reader ว่า slice ที่คืนจาก Read() อาจใช้ backing array ร่วมกับการอ่านรอบถัดไปได้ เหมือนร้านที่ล้างถาดแล้วใช้ถาดเดิมรับอาหารจานใหม่ ข้อแลกเปลี่ยนคือเราไม่ควรเก็บถาดนั้นไว้เป็นข้อมูลเก่า

เอกสารใช้คำว่า may be shared จึงห้ามเขียนโค้ดที่พึ่งว่ามันจะ alias เสมอหรือไม่ alias เลย ถ้าต้องเก็บ record ไว้หลังเรียก Read() อีกครั้ง ให้ clone slice ก่อน ตัวอย่างอ่านจาก string เท่านั้น ไม่แตะไฟล์จริง และทดสอบค่าที่เก็บว่าคงเดิม

package main

import (
    "encoding/csv"
    "fmt"
    "io"
    "strings"
)

func main() {
    reader := csv.NewReader(strings.NewReader("alpha,1\nbeta,2\n"))
    reader.ReuseRecord = true
    saved := make([][]string, 0, 2)
    for {
        row, err := reader.Read()
        if err == io.EOF { break }
        if err != nil { panic(err) }
        saved = append(saved, append([]string(nil), row...))
    }
    if saved[0][0] != "alpha" || saved[1][0] != "beta" {
        panic("record ownership was lost")
    }
    fmt.Println(saved)
}

เลือกโหมดตามอายุข้อมูล

ถ้า pipeline ตรวจและส่งต่อแต่ละแถวทันทีโดยไม่เก็บ reference หลังรอบอ่าน ReuseRecord=true ช่วยลด allocation ของ slice ได้ แต่ string ของแต่ละ field ยังมีต้นทุนของมันเอง และผลจริงขึ้นกับ workload ควร benchmark ด้วย CSV จริงก่อนสรุปว่าคุ้ม หากต้องเก็บ record เป็นชุดอยู่แล้ว การ clone ทุกแถวอาจคืนต้นทุน allocation ที่หวังประหยัด จึงอาจปล่อยค่า default ให้อ่านง่ายกว่า

อย่าสับสน ReuseRecord กับการอ่านไฟล์ทั้งหมดผ่าน ReadAll(): งาน streaming ควรประมวลผลแถวละรอบเพื่อจำกัด memory เมื่อมี parse error, Read() อาจคืน partial record พร้อม error ตามเอกสาร ต้องจัดการ error ก่อนนำค่าไปใช้ในระบบจริง และระวังข้อมูล CSV จากผู้ใช้ที่มีขนาดหรือจำนวน field ไม่คาดคิด

Recap

  • ใช้ ReuseRecord เฉพาะเมื่ออายุ record ไม่ข้ามรอบอ่าน
  • clone slice ก่อนเก็บไว้ภายหลัง
  • จัดการ io.EOF แยกจาก parse error
  • benchmark allocation กับข้อมูลจริงก่อนเปิดใน production