Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ Ruby Fibers: เพิ่มประสิทธิภาพและ Concurrency ด้วยการควบคุมละเอียด

หากคุณต้องการดึงประสิทธิภาพสูงสุดจากโปรเจกต์ Ruby ของคุณ เราต้องสำรวจ fibers และวิธีที่พวกมันทำงาน

มาเริ่มด้วยคำถามง่ายๆ...

Fibers คืออะไร?

Fibers คือผู้ทำงาน (workers) พวกมันรันโค้ดและติดตามความคืบหน้าของตัวเอง กล่าวอีกนัยหนึ่ง fibers เป็นกลไก concurrency (คอนคอร์เรนซี)

ใช่!

เหมือนกับ threads (เธรด) แตต่างตรงที่คุณมีการควบคุม fibers มากกว่า threads

ในความหมายไหนที่คุณมีการควบคุมมากกว่า?

จริงๆ แล้ว

ระบบปฏิบัติการของคุณตัดสินใจว่าจะรัน threads เมื่อไหร่ และหยุดพวกมันเมื่อไหร่

นั่นไม่ใช่กรณีกับ fibers!

คุณต้องบอก fiber ว่าพอดีรันเมื่อไหร่ และหยุดเมื่อไหร่

Fibers vs Threads

Threads รู้สึกเหมือนว่าพวกมันรันในพื้นหลัง ทำงานของพวกมัน

Fibers ไม่ทำอย่างนั้น

ขณะที่ fiber กำลังรัน มันจะกลายเป็นโปรแกรมหลักจนกว่าคุณจะหยุดมัน

มาดูตัวอย่างโค้ด!

การใช้ Fibers: ตัวอย่าง

สร้าง fiber ด้วย Fiber.new และบล็อก

ตัวอย่าง:

f = Fiber.new { puts 1 }

จากนั้นรัน fiber โดยใช้เมธอด resume

แบบนี้:

f.resume

สิ่งนี้พิมพ์ 1 และส่งคืนการควบคุมไปยังโปรแกรมหลักของคุณ

แตคุณหยุด fiber ยังไง?

ด้วยเมธอด Fiber.yield ซึ่งแตกต่างจากคีย์เวิร์ด yield ที่ใช้สำหรับบล็อก

ตัวอย่าง:

f = Fiber.new { puts 1; Fiber.yield; puts 2 }
f.resume # 1
f.resume # 2

สิ่งนี้จะพิมพ์ 1 หลังจากเริ่ม fiber ด้วย resume แล้วหยุด

หากคุณเรียก resume อีกครั้ง...

มันจะดำเนินต่อจากที่หยุดไว้พอดี และพิมพ์ 2

หมายเหตุ: การ resume fiber นี้อีกครั้ง ทำให้เกิด FiberError: dead fiber called เพราะไม่มีโค้ดเหลือให้รัน

นี่คือเหตุผลที่ fibers มีประโยชน์!

การเรียก Fiber.yield ภายใน fiber เหมือนกดปุ่ม pause (หยุดชั่วคราว) อนุญาตให้คุณหยุดกลางลูป หรือโค้ดใดๆ ที่คุณเขียนภายในบล็อกของ fiber

Fibers และ Loops: ลำดับไม่มีที่สิ้นสุด

เราสามารถใช้เอฟเฟกต์ "ปุ่ม pause" นี้เพื่อสร้างลำดับไม่มีที่สิ้นสุด (infinite sequence)

ส่วนผสม:

  • Fibers
  • Loop
  • Counter

ตัวอย่าง เลขแฟกทอเรียล (factorial numbers):

factorial = Fiber.new do
  count = 1
  loop do
    Fiber.yield (1..count).inject(:*)
    count += 1
  end
end

คุณสามารถใช้ fiber นี้หลายครั้งเท่าที่ต้องการ ด้วยเมธอด resume เพื่อได้หมายเลขถัดไปในลำดับ

ตัวอย่าง:

Array.new(5) { factorial.resume } # [1, 2, 6, 24, 120]

เยี่ยม!

Fibers และ IO: การดำเนินการ Async

Fibers เร็วและมีประสิทธิภาพกว่า threads สำหรับสิ่งที่คุณต้องรอ เช่น การเชื่อมต่อเครือข่าย

ทำไม?

เพราะ fibers ทำให้เกิด context switches น้อยกว่า

Context switch คือเมื่อ CPU เปลี่ยนจากงานปัจจุบันไปงานอื่น

สิ่งนี้มีค่าใช้จ่ายน้อย แตสะสมกันไป!

ผมทดสอบบ้างโดยใช้ perf tool ของ Linux และพบว่าในแอปพลิเคชัน Ruby 単純 fibers สร้าง context switches น้อยกว่า threads 3 เท่า

ดูดีไหม?

คุณสามารถเริ่มใช้ fibers ตอนนี้:

  • ด้วยเมธอด IO.select + รูปแบบการออกแบบ Reactor
  • กับ async gem
  • กับ falcon application server

จำไว้...

ไม่มี magic bullets (วิธีแก้ไขทุกอย่าง) แตคุ้มค่าที่จะทดสอบและดูว่า fibers ทำอะไรให้คุณได้ 🙂

สรุป

คุณได้เรียนรู้เกี่ยวกับ Fibers ใน Ruby แล้ว! Fiber ช่วยให้คุณสร้างหน่วยโค้ดที่สามารถ หยุดชั่วคราวและเริ่มต่อได้ตามความต้องการของคุณ

ตอนนี้ถึงคุณลองทำดูสิ

ขอบคุณที่อ่าน!