ห่างหายไปนาน เนื่องจากอาการป่วยเรื้อรัง วันนี้พอมีเวลาเลยจะมาเล่าสู่กันฟังเรื่อง Single-Thread กับ Multi-Thread และทำไมเรื่องนี้มันถึงทำให้ Node.js เฟื่องฟูขึ้นมาในช่วงหลังๆ
ยกตัวอย่างภาษาที่ใกล้ตัวที่สุดอย่าง JavaScript หรือ Node.js นั้นเป็นการทำงานแบบ Single-Thread และภาษายอดนิยมในสมัยก่อนอย่าง PHP นั้นมีการทำงานแบบ Multi-Thread เดี๋ยวเรามาลองดูกันว่ามันทำงานต่างกันอย่างไร และข้อดีข้อเสียของแต่ละแบบคืออะไร
Single-Thread (Event-Loop)
มาเริ่มกันที่ฝั่งของ Single-Thread กันก่อน ขอยกตัวอย่างจาก Node.js ซึ่งโดยปกติแล้วเราจะต้อง Run Application ขึ้นมาก่อน โดยมันก็จะมีการกิน CPU & RAM ในระดับหนึ่ง จากนั้นตัว Node.js ใช้ความสามารถของ Event Loop ในการรับ request ที่เข้ามา ซึ่งนั่นเป็นเบื้องหลังว่าทำไม Single-Thread Applicatyion ถึงรองรับ request แบบ parallel ได้ มันทำงานยังไงลองดูตามนี้โลด
request1 -> make db request1
request2 -> make db request2
request3 -> make db request3
db? response -> request? send response
db? response -> request? send response
db? response -> request? send response
ซึ่งภาระส่วนใหญ่จะไปตกอยู่ที่ Database เป็นหลัก เพราะเมื่อยิง Database Request ออกไปตัว Application ก็จะสามารถไป process งานอื่นๆต่อได้ทันที ซึ่งก็ไม่ได้หนักมากทำให้การทำงานของ CPU แทบจะไม่ได้มีผลกระทบใดๆเลย และตัว DB Engine เองก็ทำงานแบบ Multi-Thread อยู่แล้วนั่นเอง
ถ้าใครยังไม่ค่อยเข้าใจเรื่อง Event-Loop คลิก อ่านช่วงท้ายๆ
ข้อดี
กิน Memory น้อยเพราะไม่ต้อง Spawn Thread ใหม่ในทุกๆ request และเมื่อใช้ Memory น้อยก็ทำให้รับ request ได้เยอะขึ้ัน
ข้อเสีย
- เมื่อเราต้องทำงานที่ต้องใช้ CPU หนักๆจะทำให้การทำงานโดยรวมช้าลง ตัวอย่างงานที่ใช้ CPU เยอะๆ เช่น render3D, encode music file อะไรทำนองนี้
- ตามชื่อของมันเลยครับ Single-Thread มันทำงานบน Single-Core CPU ทำให้ต่อให้เครื่องคุณมี 10–20 Core ก็ไม่ทำให้ Single-Thread Application ของคุณทำงานได้เร็วหรือแรงขึ้นเลย…
- เมื่อมี Request ใดที่ทำให้ Application Failed อาจทำให้ Request อื่นๆไม่สามารถ Process ต่อได้หรืออาจกระทบกับทั้งระบบให้ไม่สามารถรับ Request ต่อๆไปได้ ซึ่งต้องทำการ Restart Application ใหม่
Single-Thread (Event Loop) เปรียบเสมือนร้านขายชานม ที่มีพนักงานคนเดียว คุณสามารถสั่งชาและรับบัตรคิวเอาไว้ และเดินไปไหนก็ได้ เมื่อพร้อมดื่มพนักงานจะโทรเรียกเอง ไม่ต้องยืนรอ
Multi-Thread
มาถึงตรงนี้หลายๆคนอาจจะสงสัยว่า Single-Thread มีข้อเสียเยอะมาก แต่ทำไม Node.js ถึงมานิยมมากขึ้นในช่วงหลังๆ มาครับเรามาลองดูทางฝั่ง Multi-Thread กันบ้างดีกว่าว่ามันทำงานยังไง
request1 -> spawn thread -> make db request & wait -> send response
request2 -> spawn thread -> make db request & wait -> send response
request3 -> spawn thread -> make db request & wait -> send response
จะเห็นว่าในทุก Request จะมีการ Spawn Thread ใหม่เสมอ แต่การทำงานส่วนใหญ่ก็จะยังไปลงกับ Database Request ทำให้การทำงานของ CPU จะไม่ได้แตกต่างกับ Single-Thread มากนัก แต่ก็จำเป็นจะต้องจอง Memory สำหรับการทำงานในแต่ละ Thread แยกออกจากกัน ซึ่งอาจจะไม่ได้ใช้เยอะมากเหมือนกัน Start Application แต่มันก็ไม่น้อยนะเอ้อ
ข้อดี
แต่ละ Thread ทำงานแยกจากกันทำให้ถ้า Thread ใดตาย ก็จะไม่กระทบกับการทำงาน Thread หรือ Request อื่นๆ
ข้อเสีย
- เมื่อแต่ละ Thread จะต้องทำการจอง Memory ของตัวเอง ลองนึกสภาพว่าถ้ามี Request เข้ามาเยอะๆ และแต่ละ Request/Thread จะต้องจอง Memory สำหรับตัวแปรต่างๆอีกคิดดูว่าจะมีการใช้งาน Memory มหาศาลขนาดไหน ซึ่งเมื่อ Memory ถูกใช้เยอะ ก็จะทำให้จำนวน Request ที่รับได้นั้นน้อยลงไปด้วย
- ลองมานึกถึงภาษาที่ต้องมีการ Process ก่อนอย่าง PHP ก็จะยิ่งทำให้เปลือง Memory เข้าไปอีกเพราะต้องแบ่งไปให้ PHP Runtime ในการทำงานด้วยนั่นเอง
Multi Thread เปรียบเสมือนร้านขายชานม ที่มีพนักงานขายหลายคน สามารถรับลูกค้าได้พร้อมกันมากกว่า 1 คน แต่ลูกค้าจะต้องต่อคิวรอรับชาในทันทีและห้ามออกจากแถวไปก่อน
Scaling
จากที่ผมอธิบายไปข้างต้นจะเห็นว่าจริงๆแล้วมันไม่ได้มีใครที่ชนะกันอย่างขาดลอย เพียงแต่ว่าในทรัพยากรที่จำกัด Single-Thread ของ Node.js จะทำงานได้มีประสิทธิภาพกว่านั่นเอง นั่นเป็นเหตุผลว่าทำไมมันถึงเริ่มนิยมขึ้นมาในช่วง 3–4 ปีหลังมานี้นั่นเอง
แต่จริงๆแล้วการ Scaling ก็จะเข้ามาช่วยแก้ปัญหาของทั้ง 2 แบบได้ แต่เราก็จะต้องเลือกให้ถูกวิธีด้วยเช่นกัน ซึ่งสามารถทำได้หลายแบบทั้ง Vertical/Horizontal Scaling
Multi-Thread สามารถคั่นด้วย Gateway/Load Balance ที่ทำตัวเองเป็น Event Loop ในการ Handle Request อย่าง nginx หรือทางเลือกสุดท้าย คือ “เงิน” แก้ปัญหาได้ทุกสิ่ง อัด CPU Core และ Memory เข้าไปเยอะๆ
Single-Thread เองก็มีทางแก้มากมาย เช่น แทนที่จะหาทางให้มันทำ Multi-Thread เราก็ Run Application ไว้หลายๆตัวตามจำนวน Core แทนแล้วเอา Load Balance มาคั่นอีกที หรือถ้าใช้ Cloud Provider ในปัจจุบันยิ่งเหมาะ เปิดเครื่องเล็กๆหลายๆเครื่อง ยิ่งสมัยนี้มี Auto-Scaling ทำจะ Spawn เครื่องและ Start Application ให้เองเมื่อถึง limit ที่ตั้งไว้ พร้อมเอา Load Balance มาจิ้มให้อีก หรือสุดท้ายก็ใช้ “เงิน” แก้เหมือนเดิมเปิดเครื่องทิ้งไว้เลยหลายๆเครื่องแล้วเอา Load Balance จิ้มค้างไว้เลยไม่ต้องวุ่นวาย
สรุป
ก็จบกันไปแล้วครับมาเล่าสู่กันฟังคร่าวๆ ระหว่าง Single-Thread vs Multi-Thread ซึ่งตรงไหนผิดพลาดประการใดก็ ติชม แนะนำ เป็นความรู้เพิ่มเติมได้เหมือนเดิมครับ