ลดการจัดสรร: 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- สแตกกับฮีปและการวิเคราะห์การหลุดพ้น
- โมเดลหน่วยความจำของ Go และ Happens-Before
- ภายในตัวเก็บขยะ
- ลดการจัดสรร: sync.Pool และ Arena