0Pricing
Go Academy · บทเรียน

ลดการจัดสรร: sync.Pool และ Arena

นำออบเจ็กต์กลับมาใช้ใหม่ด้วย sync.Pool และลดแรงกดดันต่อ GC

ลดการจัดสรร: sync.Pool และ Arena เป็นบทเรียน Go Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Go Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดจึงควรลดการจองหน่วยความจำ

การจองหน่วยความจำบนฮีปแต่ละครั้งจะก่อให้เกิดงานของ GC ในภายหลัง การลดการจองหน่วยความจำช่วยลดความถี่ของ GC และระยะเวลาที่หยุดชั่วคราว ทำให้ปริมาณงานและเวลาแฝงส่วนปลายในบริการที่มีการใช้งานสูงดีขึ้น

ทำโปรไฟล์ก่อน

ทำโปรไฟล์ก่อนปรับปรุงประสิทธิภาพเสมอ ใช้ go test -benchmem และโปรไฟล์ฮีป -alloc_space เพื่อค้นหาเส้นทางการจองหน่วยความจำที่เป็นคอขวดจริง อย่าปรับปรุงโดยอาศัยเพียงสัญชาตญาณ

sync.Pool

sync.Pool คือพูลออบเจ็กต์ที่นำกลับมาใช้ซ้ำได้และปลอดภัยต่อการทำงานพร้อมกัน ใช้สำหรับออบเจ็กต์อายุสั้นที่มักถูกจองและทิ้งบ่อย ๆ เช่น บัฟเฟอร์ไบต์ แผนที่ชั่วคราว และบริบทคำขอ

var pool = sync.Pool{
    New: func() any { return &bytes.Buffer{} },
}
func process(data []byte) {
    buf := pool.Get().(*bytes.Buffer)
    buf.Reset()
    buf.Write(data)
    // use buf...
    pool.Put(buf)
}

พูลไม่ใช่แคช

GC อาจล้างรายการในพูลเมื่อใดก็ได้ พูลมีไว้เพื่อลดแรงกดดันจากการจองหน่วยความจำ ไม่ใช่สำหรับแคชข้อมูลอายุยืน ออบเจ็กต์ที่ดึงมาอาจมาจากโกโรทีนใดก็ได้

ใช้ Reset ก่อนนำกลับมาใช้ซ้ำทุกครั้ง

ล้างออบเจ็กต์ในพูลก่อนใช้งาน เพราะอาจมีข้อมูลจากผู้เรียกใช้คนก่อนอยู่ สำหรับ bytes.Buffer ให้เรียก Reset() ส่วนสไลซ์ให้ปรับขนาดใหม่เป็น [:0]

การจองสไลซ์ล่วงหน้า

จองสไลซ์ล่วงหน้าด้วย make([]T, 0, n) เมื่อทราบความยาวสุดท้าย การทำเช่นนี้ช่วยหลีกเลี่ยงการเพิ่มขนาดเป็นสองเท่าและการคัดลอกซ้ำ ๆ ขณะที่สไลซ์ขยายตัว

results := make([]Result, 0, len(input)) // no reallocations

ตัวสร้างสตริง

ใช้ strings.Builder แทนการต่อสตริง เพื่อหลีกเลี่ยงการจองสตริงชั่วคราวภายในลูป:

var sb strings.Builder
for _, s := range parts { sb.WriteString(s) }
result := sb.String()

การใช้พูลกับ bytes.Buffer

bytes.Buffer เป็นชนิดที่มักนำมาใช้กับพูลมากที่สุดชนิดหนึ่ง ใช้พูลกับชนิดนี้เพื่อหลีกเลี่ยงการจองหน่วยความจำซ้ำ ๆ ในการเข้ารหัส JSON การสร้างการตอบกลับ HTTP และการประมวลผลแม่แบบ

อารีนา Go (ทดลอง)

Go 1.20 ขึ้นไปมีแพ็กเกจอารีนาทดลอง (golang.org/x/exp/arena) อารีนาจะจองออบเจ็กต์จำนวนมากไว้ในบล็อกขนาดใหญ่เพียงบล็อกเดียว ซึ่งสามารถคืนหน่วยความจำทั้งหมดได้ในครั้งเดียว โดยไม่ต้องผ่าน GC แยกเป็นรายออบเจ็กต์

ชนิดค่า

โครงสร้างขนาดเล็กที่ส่งผ่านด้วยค่าจะหลีกเลี่ยงการจองหน่วยความจำบนฮีปได้ทั้งหมด หลีกเลี่ยงรูปแบบพอยน์เตอร์ไปยังโครงสร้างขนาดเล็กในโค้ดที่ทำงานบ่อย เพราะการส่งคืนค่าอาจมีต้นทุนต่ำกว่า

การวัดผลกระทบ

เรียกใช้การวัดประสิทธิภาพด้วย -benchmem ทั้งก่อนและหลังการเปลี่ยนแปลง แล้วเปรียบเทียบด้วย benchstat ตั้งเป้าลด allocs/op ในเส้นทางการทำงานที่เป็นคอขวด ไม่ใช่เพียงลด ns/op

BenchmarkProcess-8  1000000  125 ns/op  64 B/op  2 allocs/op
// After pooling:
BenchmarkProcess-8  1000000   48 ns/op   0 B/op  0 allocs/op

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ลักษณะสำคัญใดที่ทำให้ sync.Pool ปลอดภัยสำหรับการลดการจองหน่วยความจำ

สรุป: การลดการจองหน่วยความจำ

ประเด็นสำคัญ:

  • ทำโปรไฟล์ก่อน: ใช้ -benchmem และฮีป -alloc_space ก่อนปรับปรุงประสิทธิภาพ
  • ใช้ sync.Pool กับออบเจ็กต์ที่ถูกจองและทิ้งบ่อย ๆ และใช้ Reset ก่อนนำกลับมาใช้ซ้ำทุกครั้ง
  • จองสไลซ์ล่วงหน้าด้วย make([]T, 0, n) และใช้ strings.Builder สำหรับการต่อสตริง
  • ชนิดค่าช่วยหลีกเลี่ยงการจองหน่วยความจำบนฮีป และควรวัดประสิทธิภาพเพื่อยืนยันการปรับปรุง

คำถามที่พบบ่อย

บทเรียน “ลดการจัดสรร: sync.Pool และ Arena” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ลดการจัดสรร: sync.Pool และ Arena” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Go Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ลดการจัดสรร: sync.Pool และ Arena”

นำออบเจ็กต์กลับมาใช้ใหม่ด้วย sync.Pool และลดแรงกดดันต่อ GC คุณปฏิบัติ Go Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Go Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Go Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “ลดการจัดสรร: sync.Pool และ Arena” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Go Academy นี้ได้ไหม

ได้ บทเรียน Go Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. สแตกกับฮีปและการวิเคราะห์การหลุดพ้น
  2. โมเดลหน่วยความจำของ Go และ Happens-Before
  3. ภายในตัวเก็บขยะ
  4. ลดการจัดสรร: sync.Pool และ Arena
← กลับไปที่ Go Academy