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

คอขวดที่พบบ่อย

เร่งโค้ด Ruby

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

การระบุคอขวด

การทำงานช้าลงของ Ruby ส่วนใหญ่มาจากรูปแบบที่เกิดซ้ำอยู่ไม่กี่แบบ หากรู้จักรูปแบบเหล่านี้ คุณก็จะแก้ไขโค้ดได้อย่างรวดเร็ว

  • เลือกใช้โครงสร้างข้อมูลไม่เหมาะกับงาน
  • ทำงานซ้ำทั้งที่สามารถเก็บไว้ในแคชได้
  • การสอบถามข้อมูลแบบ N+1 และลูปซ้อนกัน

บทเรียนนี้ครอบคลุมปัญหาที่พบบ่อยที่สุด

puts 'Speeding up Ruby starts with knowing the usual suspects'

Array#include? เทียบกับเซต

การตรวจสอบสมาชิกด้วย Array#include? มีความซับซ้อน O(n) ส่วนเซต (หรือแฮช) ให้การค้นหาที่มีความซับซ้อน O(1)

  • หากต้องตรวจสอบสมาชิกซ้ำ ๆ ให้สร้างเซตเพียงครั้งเดียว
  • ช่วยเพิ่มความเร็วได้มากกับคอลเลกชันขนาดใหญ่
require 'set'

allowed = Set.new(['a', 'b', 'c'])
puts allowed.include?('b')
puts allowed.include?('z')

ลูปซ้อนกัน (O(n ยกกำลังสอง))

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

  • แทนที่ลูปด้านในด้วยการค้นหาในแฮช
  • เปลี่ยนความซับซ้อนจาก O(n ยกกำลังสอง) เป็น O(n)
a = [1, 2, 3, 4]
b = [3, 4, 5]
set_b = b.to_set rescue require('set') || b.to_set
common = a.select { |x| set_b.include?(x) }
puts common.inspect

รูปแบบ N+1

การดึงข้อมูลที่เกี่ยวข้องภายในลูปทำให้เกิดการดำเนินการ N+1 ครั้ง

  • สอบถามข้อมูล 1 ครั้งสำหรับรายการ จากนั้นสอบถามอีก 1 ครั้งต่อสมาชิกแต่ละตัว
  • เปลี่ยนเป็นดึงข้อมูลแบบรวมกลุ่มด้วยการสอบถามเพียงครั้งเดียว
# Bad: lookup inside loop
orders = [1, 2, 3]
prices = { 1 => 10, 2 => 20, 3 => 30 }
# Good: one preloaded hash, O(1) per item
total = orders.sum { |id| prices[id] }
puts total

การจดจำผลลัพธ์

การคำนวณค่าที่ใช้ทรัพยากรสูงซ้ำ ๆ เป็นการเสียเวลา ให้จดจำผลลัพธ์ด้วย ||=

  • เก็บผลลัพธ์ไว้ในแคชหลังจากคำนวณครั้งแรก
  • การเรียกใช้ครั้งต่อ ๆ ไปจะคืนค่าทันที
class Report
  def total
    @total ||= begin
      puts 'computing...'
      (1..1000).sum
    end
  end
end

r = Report.new
puts r.total
puts r.total

การเลือกเมธอดที่เหมาะสม

เมธอดสำหรับประมวลผลสมาชิกบางเมธอดทำงานเร็วกว่าการเชื่อมเมธอดหลายตัวต่อกันมาก

  • sum เร็วกว่า inject(:+)
  • any? จะหยุดทำงานทันทีเมื่อได้คำตอบ ต่างจาก select.empty?
  • find จะหยุดเมื่อพบสมาชิกที่ตรงกันตัวแรก
nums = (1..1_000_000)
puts nums.any? { |n| n > 5 }
puts nums.find { |n| n > 5 }

หลีกเลี่ยงการเรียงลำดับซ้ำ

การเรียงลำดับภายในลูปหรือเรียงซ้ำหลายครั้งใช้ทรัพยากรมาก ให้เรียงลำดับเพียงครั้งเดียวแล้วนำผลลัพธ์กลับมาใช้ซ้ำ

  • การเรียงลำดับมีความซับซ้อน O(n log n)
  • เก็บผลลัพธ์ที่เรียงแล้วไว้ในแคช หากข้อมูลไม่มีการเปลี่ยนแปลง
data = [5, 2, 8, 1, 9]
sorted = data.sort
puts sorted.first
puts sorted.last

การจัดกลุ่มด้วยแฮช

group_by และ tally รวบรวมข้อมูลได้ในการวนดูเพียงรอบเดียว แทนการตรวจดูซ้ำหลายครั้ง

  • tally นับจำนวนครั้งที่ปรากฏได้อย่างมีประสิทธิภาพ
  • ช่วยหลีกเลี่ยงลูปนับจำนวนที่เขียนขึ้นเอง
words = ['a', 'b', 'a', 'c', 'b', 'a']
puts words.tally.inspect

ต้นทุนการสร้างสตริง

การรวมด้วย join เร็วกว่าการต่อสตริงซ้ำ ๆ เมื่อทำงานกับคอลเลกชัน

  • สร้างอาร์เรย์ก่อน แล้วใช้ join เพียงครั้งเดียว
  • ช่วยหลีกเลี่ยงการสร้างสตริงชั่วคราวจำนวนมาก
parts = (1..5).map { |i| "item#{i}" }
puts parts.join(', ')

การคอมไพล์นิพจน์ทั่วไป

การกำหนดลิเทอรัลนิพจน์ทั่วไปไว้ในลูปที่ทำงานบ่อยจะทำให้เกิดการคอมไพล์ซ้ำโดยปริยาย ย้ายไปไว้เป็นค่าคงที่

  • คอมไพล์ครั้งเดียว แล้วจับคู่ได้หลายครั้ง
  • ใช้ match? เมื่อคุณต้องการเพียงค่าจริงหรือเท็จ
EMAIL = /\A[^@\s]+@[^@\s]+\z/

inputs = ['a@b.com', 'nope', 'x@y.org']
valid = inputs.select { |s| EMAIL.match?(s) }
puts valid.inspect

เลื่อนการประมวลผลที่ไม่จำเป็น

อย่าคำนวณสิ่งที่คุณอาจไม่ได้ใช้ ให้เลื่อนการทำงานด้วยการประเมินเมื่อจำเป็นหรือใช้เงื่อนไขตรวจสอบ

  • คืนค่ากลับทันทีเมื่อทำได้
  • คำนวณค่าที่ใช้ทรัพยากรสูงเมื่อต้องการเท่านั้น
def describe(items)
  return 'empty' if items.empty?
  "#{items.size} items, first is #{items.first}"
end

puts describe([])
puts describe([10, 20])

ตรวจสอบความเข้าใจ

ทดสอบความรู้เกี่ยวกับคอขวดของคุณ

สรุปทบทวน

คุณได้เรียนรู้วิธีแก้ไขคอขวดที่พบบ่อยแล้ว:

  • ใช้เซตหรือแฮชเพื่อตรวจสอบสมาชิกอย่างรวดเร็ว แทน include?
  • กำจัดลูปซ้อนกันและรูปแบบ N+1 ด้วยแฮชที่เตรียมข้อมูลไว้ล่วงหน้า
  • จดจำผลลัพธ์ของการคำนวณที่ใช้ทรัพยากรสูงด้วย ||=
  • เลือกเมธอดที่มีประสิทธิภาพ (sum, any?, tally) และย้ายนิพจน์ทั่วไปออกจากลูป
  • เลื่อนหรือตัดการทำงานที่คุณอาจไม่จำเป็นต้องใช้

วัดผลก่อนและหลังเสมอเพื่อยืนยันว่าประสิทธิภาพดีขึ้น

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

บทเรียน “คอขวดที่พบบ่อย” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “คอขวดที่พบบ่อย”

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

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

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

บทเรียน “คอขวดที่พบบ่อย” ใช้เวลานานแค่ไหน

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

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

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

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

  1. การวัดประสิทธิภาพ
  2. เครื่องมือวิเคราะห์ประสิทธิภาพ
  3. การปรับหน่วยความจำให้เหมาะสม
  4. คอขวดที่พบบ่อย
← กลับไปที่ Ruby Academy