[Ruby] ลอง async gem

Teerayut Hiruntaraporn
1 min readJan 25, 2021

--

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
end
puts 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
end
Async 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
end
Async 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
end
Async 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 หลายๆ ที่ที่บอกว่าประสิทธิภาพค่อนข้างดี ก็อาจจะต้องทดสอบงานที่วุ่นวายมากขึ้นว่าจะทำงานได้ดีเพียงใด

--

--

Teerayut Hiruntaraporn
Teerayut Hiruntaraporn

No responses yet