Synchronous กับ Asynchronous ต่างกันอย่างไร
หากคุณยังสงสัยว่า Synchronous เหมือนหรือต่างจาก Asynchronous ยังไงบทความนี้จะให้คำตอบนั้นกับคุณ
สวัสดีครับผมชื่อบูม นี่เป็นบทความแรกของผมในปี 2020 ผมตั้งใจว่าปีนี้จะปล่อยบทความให้ได้สัก 30 บทความที่เกี่ยวกับ Programming ถ้าอ่านแล้วชื่นชอบก็อย่าลืมกด Like กด Share แล้วก็กด Follow กันไว้ด้วยนะครับ รับรองว่าจะปล่อยบทความที่ย่อยง่ายๆ มาให้เสพกันเรื่อยๆ ทั้งปีเลย
ในโลกของการเขียนโปรแกรมเราสามารถแบ่งการดำเนินงานของโปรแกรมออกเป็นสองอย่างด้วยกันก็คือ Synchronous กับ Asynchronous แล้วการดำเนินงานทั้งสองอย่างนี้มันเหมือนหรือแตกต่างกันอย่างไรเรามาหาคำตอบไปพร้อมๆ กันครับ
- Synchronous หรือ Blocking จะดำเนินการรันโปรแกรมทีละชุดคำสั่ง และจะไม่รันชุดคำสั่งต่อไปถ้ายังรันชุดคำสั่งปัจจุบันไม่จบ ตัวอย่างเช่น ถ้าโปรแกรมเรียกฟังก์ชัน A(); และ B(); ตามลำดับ โปรแกรมจะไม่รันฟังก์ชัน B(); จนกว่าฟังก์ชัน A(); จะทำงานเสร็จ
- Asynchronous หรือ Non-blocking จะดำเนินการรันโปรแกรมทีละชุดคำสั่ง และจะรันชุดคำสั่งถัดไปทันทีโดยไม่จำเป็นต้องรอชุดคำสั่งก่อนหน้าทำงานเสร็จ ตัวอย่างเช่น ถ้าโปรแกรมเรียกฟังก์ชัน A(); และ B(); ตามลำดับ โปรแกรมจะรันฟังก์ชัน A(); และ B(); ตามลำดับโดยไม่สนใจว่าฟังก์ชัน A(); จะทำงานเสร็จรึยัง จะไปเรียกฟังก์ชัน B(); ต่อเลยทันที
สรุป Synchronous จะรอคำสั่งก่อนหน้าทำงานเสร็จก่อนถึงจะรันคำสั่งต่อไปได้ ส่วน Asynchronous นั้นรันต่อไม่รอแล้วนะ …
Synchronous ก็ดูไม่เดือดร้อนจะมี Asynchronous ไปทำไม
แน่นอนว่าหลายคนคงเกิดคำถามในใจว่าทำไมต้องใช้ Asynchronous ในเมื่อ Synchronous ก็เป็นรูปแบบที่ดีตรงไปตรงมานี่นา เรามาหาคำตอบจากภาพด้านล่างนี้กันครับ
ภาพด้านบนเป็นการเปรียบเทียบการทำงานระหว่าง Synchronous (ฝั่งซ้าย) และ Asynchronous (ฝั่งขวา) เรามาวิเคราะห์ไปพร้อมๆ กันดีกว่าครับ
- Synchronous จากภาพจะเห็นว่าโปรแกรมจะรันชุดคำสั่งที่ 2 ได้นั้นจะต้องรันชุดคำสั่งที่ 1 เสร็จก่อน และถ้าจะรันชุดคำสั่งที่ 4 ได้นั้นจะต้องรันชุดคำสั่งที่ 1 2 3 เสร็จก่อนตามลำดับ ซึ่งหมายความว่ากว่าจะรันชุดคำสั่งที่ 4 ได้นั้นจะต้องรอตั้ง 37 วินาที (20 + 7 + 10) ทำให้ระยะเวลารวมในการรันโปรแกรมเท่ากับ 45 วินาที
- Asynchronous จากภาพจะเห็นว่าโปรแกรมจะรันชุดคำสั่งที่ 1 2 3 4 ได้เลยโดยที่ไม่ต้องรอชุดคำสั่งก่อนหน้าทำงานเสร็จก่อน ซึ่งหมายความว่าชุดคำสั่งที่ 4 จะรันได้เลยไม่ต้องรอ 37 วินาที แบบ Synchronous ในเมื่อไม่ต้องรอชุดคำสั่งอื่นๆ ทำงานก็เปรียบเสมือนชุดคำสั่ง 1 2 3 4 ถูกเรียกทำงานพร้อมกัน ทำให้ระยะเวลารวมในการรันโปรแกรมใช้เพียง 20 วินาที (เท่ากับระยะเวลาที่รันชุดคำสั่งที่ 1 หรือชุดคำสั่งที่รันนานที่สุดนั่นเอง)
สรุป Asynchronous ทำงานได้เร็วกว่า Synchronous เนื่องจากไม่ต้องรอชุดคำสั่งก่อนหน้าทำงานเสร็จก่อน กล่าวคือ Asynchronous มาช่วยเรื่องความเร็วของโปรแกรมนั่นเอง …
ถ้า Asynchronous เร็วกว่าก็ไม่จำเป็นต้องใช้ Synchronous แล้วรึเปล่า
เมื่อเรารู้ว่า Asynchronous ดำเนินงานได้รวดเร็วกว่า Synchronous แถมโปรแกรมยังทำงานได้เหมือนกัน แล้วทำไมเราถึงยังต้องใช้ Synchronous อยู่ล่ะ เรามาหาคำตอบกันต่อเลยครับ
จากโปรแกรมข้างต้น ผมขอใช้ภาษา JavaScript ในการยกตัวอย่างการดำเนินงานแบบ Asynchronous และ Synchronous โดยภาษา JavaScript หากเรียกใช้ Timer โปรแกรมจะทำงานแบบ Asynchronous ทันที ในส่วนนี้ผมไม่ขอลงรายละเอียดลึกไปกว่านี้ เนื่องจากอยากให้โฟกัสปัญหาของ Asynchronous ในโปรแกรมข้างต้นมากกว่าครับ
งั้นก่อนอื่นเรามาทำความเข้าใจการทำงานของฟังก์ชันต่างๆ ในโปรแกรมนี้กันครับ
- setDataAsync(); เป็นฟังก์ชันที่ทำงานแบบ Asynchronous โดยจะทำการ set ค่าให้กับตัวแปร data เมื่อเวลาผ่านไป 1 วินาที
- setDataSync(); เป็นฟังก์ชั่นที่ทำงานแบบ Synchronous โดยจะทำการ set ค่าให้กับตัวแปร data ทันที
- printData(); เป็นฟังก์ชั่นที่ทำงานแบบ Synchronous โดยจะทำการ print ค่าของตัวแปร data ออกมาแสดงผลทันที
#1 Test Asynchronous
1: printData(); // print data จะได้ `data = 0`2: setDataAsync(1); // set data เท่ากับ 1 เมื่อเวลาผ่านไป 1 วินาที3: printData(); // print data จะได้ `data = 0`
จะเห็นได้ว่าฟังก์ชัน printData(); ในบรรทัดที่ 3 ยังคง print ค่า `data = 0` เพราะเนื่องจากการดำเนินงานแบบ Asynchronous ทำให้ไม่ต้องรอ setDataAsync(1); ในบรรทัดที่ 2 ทำงานเสร็จก่อนนั่นเอง ทุกคนเห็นไหมครับว่านี่มันคือปัญหาใหญ่หลวงตั้งใจที่จะ set ค่าแท้ๆ แต่ค่าที่เซตกลับไม่สามารถนำมาใช้ :(
#2 Test Synchronous
1: printData(); // print data จะได้ `data = 0`2: setDataSync(2); // set data เท่ากับ 2 ทันที3: printData(); // print data จะได้ `data = 2`
จะเห็นได้ว่าฟังก์ชัน printData(); ในบรรทัดที่ 3 print ค่า `data = 2` ตามที่เราต้องการแล้ว เนื่องจากการทำงานแบบ Synchronous ทำให้ชุดคำสั่งในบรรทัดที่ 3 จำเป็นจะต้องรอ setDataSync(2); ในบรรทัดที่ 2 ทำงานเสร็จก่อนถึงจะสามารถรันได้ เห็นไหมครับว่า Synchronous ก็ยังจำเป็นอยู่ :)
สรุป งานที่จำเป็นต้องใช้ค่าที่ได้จากฟังก์ชันก่อนหน้าควรเลือกใช้ Synchronous เพราะถ้าหากเผลอไปใช้ Asynchronous แล้วละก็ รับรองโปรแกรมมี Bug แน่ๆ …
ข้อสรุป
- การดำเนินงานแบบ Asynchronous มีความเร็วกว่า Synchronous เนื่องจากสามารถรันชุดคำสั่งถัดไปได้ทันทีโดยไม่จำเป็นต้องรอชุดคำสั่งก่อนหน้าทำงานเสร็จก่อน
- การดำเนินงานแบบ Asynchronous ไม่เหมาะกับงานที่จำเป็นต้องรอค่าจากชุดคำสั่งก่อนหน้าเพื่อนำมาใช้กับชุดคำสั่งถัดไป (เพราะ Asynchronous ไม่รอนั่นเอง) ถ้าเจอกรณีนี้ควรเลือกใช้การดำเนินงานแบบ Synchronous
จบกันไปแล้วสำหรับบทความ Synchronous กับ Asynchronous ต่างกันอย่างไร หวังว่าผู้อ่านทุกท่านจะมีความสุขในการอ่าน และสามารถเลือกใช้ Synchronous หรือ Asynchronous ได้ถูกที่ถูกเวลา แล้วอย่าเลือกใช้ผิดกันล่ะ ไม่งั้น Bug แน่ๆ
… ขายของหน่อย ถ้าไม่อยากเจอ Bug มาจ้างพวกเราชาว Devbake ซิรับรองโปรแกรมของท่านจะเร็วแรง แถมไม่มี Bug ด้วยน้า (จะพยายาม 555) จะบอกให้ :P