[Ruby] ลอง async gem
async gem เป็น library ตัวหนึ่งของ ของภาษา ruby ที่ถูกเขียนขึ้นเพื่อทำให้ การใช้งาน IO แบบ Asynchronous ของ ruby ทำให้ง่ายขึ้น
โดยการใช้งานก็ไม่ได้มีอะไรมาก เพียงแค่สั่ง Block ดังนี้
async do
…
end
ซึ่งถ้าใช้งานครั้งแรก ตัว Library จะสร้างสิ่งที่เรียกว่า Reactor ซึ่งเป็นผู้ดูแลจัดการงานที่จะถูกทำพร้อมๆ กัน โดย Block นี้จะจบการทำงานเมื่อทุกงานใน block ทำงานเสร็จแล้ว
ทีนี้เลยมาลองโค้ดเบื้องต้นครับ โดยเป็นการเรียกเว็บจากเว็บข่าวสุดฮอต 2 ที่คือ ผู้จัดการและมติชนมา
require 'async'
require 'net/http'def load_news(url)
uri = URI url
Net::HTTP.get uri
endputs load_news 'https://mgronline.com'
puts load_news 'https://www.matichon.co.th'
ซึ่งตรงนี้จะเป็นวิธีเขียนแบบทั่วไป ผลก็คือจะไปทำการดาวน์โหลดไฟล์แสดงหน้าเว็บของทั้งสองที่มา ซึ่งตอนนี้จะใช้เวลาประมาณ
0.475, 0.453, 0.438 วินาที
จากนั้นเราก็เริ่มใส่ การทำ async เข้าไป โค้ดจะเปลี่ยนเป็น
require 'async'
require 'net/http'def load_news(url)
uri = URI url
Net::HTTP.get uri
endAsync do
Async do
puts load_news 'https://mgronline.com'
end
Async do
puts load_news 'https://www.matichon.co.th'
end
end
โดย Async Block ที่อยู่ใน Async Block ตัวนอกสุด จะเปลี่ยนหน้าที่จากเดิม เป็นการ สั่งทำงาน block ที่อยู่ภายใน แบบ Asynchronous ผ่าน Ruby Fiber
ดังนั้นสิ่งที่เกิดขึ้นคือจะเกิด Ruby Fiber ขึ้น 2 ตัวเพื่อทำการดาวน์โหลดเว็บ แทนที่จะค่อยๆ ทำไปเรื่อยๆ
ดังนั้นเวลาที่ได้ในการโหลดจึงลดลง เป็น
0.394, 0.342, 0.372 วินาที
ทีนี้เนื่องจากรู้สึกว่า code ดูน่าเกลียดไปหน่อย และเห็นว่า Async do มันซ้ำซ้อนเหลือเกิน เลยไปจับยัดเข้าไปในเมธอด load_news แทน จะได้เป็นแบบนี้
require 'async'
require 'net/http'def load_news(url)
Async do
uri = URI url
Net::HTTP.get uri
end
endAsync do
mgr = load_news('https://mgronline.com')
matichon = load_news('https://www.matichon.co.th')
puts mgr.wait
puts matichon.wait
end
จุดสำคัญคือมีการใช้ wait method ซึ่งใช้สำหรับรอรับผลลัพธ์จาก การใช้งาน Async ถ้าสังเกต ณ จุดนี้ Async จะดูคล้ายๆกับ await ของ js ขึ้นมาเล็กน้อย
วิธีนี้ก็จะได้ผลใกล้เคียงจากเมื่อสักครู่ คือ
0.376, 0.355, 0.372 วินาที
แล้วถ้าเปลี่ยนตำแหน่งของ wait ไปอยู่ใน function เลยหล่ะ
require 'async'
require 'net/http'def load_news(url)
Async do
uri = URI url
Net::HTTP.get uri
end
endAsync do
mgr = load_news('https://mgronline.com').wait
matichon = load_news('https://www.matichon.co.th').wait
puts mgr
puts matichon
end
ผลก็คือจะทำงานช้าลงเพราะไปบอกให้เขารอผลก่อนนั่นเอง
0.424, 0.475 , 0.427 วินาที
สรุปโดยภาพรวม ก็ถือว่าเป็นวิธีการเขียนที่ง่ายขึ้นมาก เมื่อเทียบกับ Concept ของ Eventmachine จริงๆ มี Benchmark หลายๆ ที่ที่บอกว่าประสิทธิภาพค่อนข้างดี ก็อาจจะต้องทดสอบงานที่วุ่นวายมากขึ้นว่าจะทำงานได้ดีเพียงใด