รู้จัก Kotlin Coroutines ตั้งแต่ Zero จนเป็น Hero : ตอนที่ 1
ก่อนอื่นเรามารู้จักการทำงานของคอมพิวเตอร์กันก่อนดีกว่า
โดยปกติการเขียนโปรแกรมนั้นการที่เราสั่งให้คอมพิวเตอร์ทำงานโปรแกรมจะทำงานจากบรรทัดบน -> ลงบรรทัดล่างตามลำดับ
เดี๋ยวก่อน .. แหม่รีบจังเลยเรามาดูกันก่อนเราจะเรียนอะไรกันบ้างพร้อมแล้วเริ่มกันเล้ย
เนื้อหาที่คุณจะได้เรียนรู้ในบทความนี้
- ข้อแตกต่างระหว่าง Synchronous และ Asynchronous
- Coroutine คืออะไร แล้วทำไมมันมาเกี่ยวอะไรกับ Synchronous และ Asynchronous ได้ยังไง
- Coroutine ไม่ใช้ได้ไหมแล้วเกิดอะไรขึ้น
- Coroutine จะมาช่วยทำให้โค้ดอ่านง่ายขึ้นได้แค่ไหน ?
- Suspend function
- Coroutine builder , Scope , Context บลาาๆ
เอาล่ะเรามาเริ่มกันเลย
ข้อแตกต่างระหว่าง Synchronous และ Asynchronous
ต่อจากเมื่อกี้ .. แล้วจะเกิดอะไรขึ้นละเช่นถ้าบรรทัดที่สองเกิดทำงานนานสัก 20 วินาที แน่นอนว่ายังไม่ต้องไปถึงบรรทัดที่ 3 โปรแกรมก็หยุดรอสิครับ
ซึ่งการทำงานลักษณะนี้เราจะเรียกว่าการเขียนโปรแกรมแบบ Blocking programming คือโปรแกรมจะหยุดรอการทำงานจนกว่าจะทำงานเสร็จถึงจะทำงานบรรทัดถัดไป หรือเรียกอีกชื่อหนึงว่า การเขียนโปรแกรมแบบ Synchronous
แล้วเมื่อไรจะเข้าเรื่อง Coroutines สักที …… ใจเยนนนนนน ขอต่ออีกนิด
ต่อมามีคนมาบอกว่าาเฮ้ยย ไปรอทำไมละกว่าจะรอบรรทัดสองเสร็จ เสียเวลาเราก็ทำมันพร้อมกันไปซะเลยสิจะได้เสร็จไวๆ มันไม่ทำงานอะไรที่มันเกี่ยวข้องกันอยู่แล้วนิ ??
จนเป็นที่มาของ พ้ามม Asynchronous แล้วมันคืออะไรละแล้วมันทำงานยังไง
เอาละเล่าไปไม่เห็นภาพมาดูนี่กันเลยด้านบนจะเป็นการเขียนโปรแกรมแบบ
Synchronous ด้านล่างจะเป็น Asynchronous
คือจะเห็นได้ว่าภาพด้านล่าง มันจะไม่สนใจเลยว่าบรรทัดก่อนหน้าตัวมันเองจะทำงานเสร็จแล้วหรือยังมันจะทำงานพร้อมกัน ซึ่งการเขียนโปรแกรมแบบนี้จะมีชื่อเรียกอีกแบบว่า Non-Blocking programming
Synchronous Programing (Blocking): การทำงานตามลำดับจนกระทั่งทำงานเสร็จสิ้น
Asynchronous Programing (Non-Blocking) : การทำงานอย่างไม่เป็นลำดับ โดยไม่คำนึงถึงว่าการทำงานลำดับก่อนหน้าเสร็จแล้วหรือไม่
หลังจากได้รู้จักความแตกต่างระหว่าง Synchronous และ Asynchronous Programing กันแล้วเรามาดูกันต่อว่ามันคืออะไรเกี่ยวอะไรยังไงกับ Coroutine
What is Coroutine
Coroutines = Co + Routines
Co มาจากคำว่า cooperation และ Routines นั้นหมายถึง functions
พอมารวมกันก็จะกลายเป็น ฟังก์ชันที่ทำงานร่วมกันกับฟังก์ชันอื่นๆ ซึ่งเราก็จะเรียกมันว่า Coroutine
จากภาพ Function A -> Function B -> Function C -> Function D เรียกกันต่อเนื่องกันไป จากนั้นจึง Call back กลับมา Function D -> Function A
บ่อยครั้งที่เราต้องมาเหนื่อยกับการเขียน Call Back มากมาย ซึ่ง Coroutine ถือเป็น Lightweight threads ตัวหนึ่งซึ่งการที่ coroutine เป็น Lightweight threads ทำให้เราสามารถเขียนโค้ดในรูปแบบ Asynchronous เขียนให้เป็นในรูปแบบ Synchronous ได้ เอาละเรามาเริ่มกันเลยย
Threads : หน่วยการทำงานย่อยของ Process
Lightweight threads : หน่วยการทำงานย่อยของ Threads
Your first coroutine with Hello world
เย้…ในที่สุดเราก็ Hello world ได้แล้ว ถ้าไม่มีอะไรผิดพลาดเราก็จะได้ผลลัพธ์หน้าตาเป็นแบบนี้
Hello,
World!
เห็นคำสั่งอะไรแว๊ปๆ ไหม
GlobalScope.launch
อดใจรอก่อนเดี่ยวเราจะเล่าให้ฟังว่ามันคือคำสั่งอะไร แต่อยากให้เห็นบรรทัด 9 มีคำสั่งให้ Thread Sleep ไป จะเกิดอะไรขึ้นละถ้ากำลังเลื่อนฟีดในหน้าจออย่างสนุกสนาน แอปจะค้างทันทีทันใด เนื่องจากเราไปสั่งการทำงานบน Main Thread
Why there is a need for Kotlin Coroutines?
ยังไม่เห็นภาพกันใช่ไหมเดี๋ยวเราจะมายกตัวอย่างที่เราเจอกันบ่อยๆ เช่น
- การดึงข้อมูล Feed มาจาก Server
- การนำข้อมูลที่ได้แสดง
จะเห็นว่าเมื่อเราใช้คำสั่งเรียก fetchAndShowFeedData จะไม่สามารถทำงานได้เกิดเหตุการ NetworkOnMainThreadException เนื่องจากตัวระบบปฏิบัติการไม่ยอมให้เราทำงานขณะที่แอปพลิเคชันกำลังทำงานบน Main Thread
ถึงแม้ว่าบางครั้งการทำงานอะไรบางอย่างที่นานๆ ตัวระบบปฏิบัติการยังยอมให้เราทำงานอยู่ก็ตามมันก็ไม่ใช่ความคิดที่ดีนัก เพราะบางครั้งอาจจะทำงานแอปพลิเคชันค้างไปเลยก็ได้ที่ทางที่ดี Process อะไรที่ทำงานบางอย่างนานๆ เราก็ควรจะพลักภาระให้ไปทำงานบน Background Thread ซะไม่พูดพล่ามทำเพลง ไปต่อกันเลยดีกว่า
การแก้ไขปัญหาที่ว่านี้มีหลากหลายวิธีไปดูแต่ละวิธีกันเล้ยย
- ใช้ Call Back สิ เอิ่มม..ถ้า Call back เยอะๆ คงจะปวดหัวกันหน้าดู
fun fetchAndShowFeedData() {
fetchFeedData { feedData ->
showFeedData(feedData)
}
}
- ใช้ RxJava สิ ในโลกของ Reactive ด้วยวิธีนี้สามารถทำให้เราแก้ปัญหาความซับซ้อนของการ Call Back ได้
fetchFeedData().subscribeOn(Schedulers.io())
.observerOn(AndroidSchedulers.mainThread())
.subscribe { feedData ->
showFeedData(feedData)
}
- มาถึงพระเอกของเราใช้ Coroutines สิ
suspend fun fetchAndShowFeedData() {
val feedData = fetchFeedData() // fetch on IO thread
showFeedData(feedData) // back on UI thread
}
สั้นๆ แค่นี้เลยหรอ ?? ใช่แล้วอ่านไม่ผิดหรอกแถมยังอ่านง่ายอีกต่างหาก
เห็นคำสั่งอะไรแว๊ปๆ ไหม
suspend fun
เดี๋ยวก่อนใจเย็นๆ ในบทความตอนต่อไปเราจะมาเล่าให้ฟังกันต่อว่าจริงๆ มันคือคำสั่งอะไรกันแน่ ??
เอาล่ะไปต่อตอนต่อไปกันเล้ย
สำหรับใครที่อดใจไม่ไหวเข้าไปอ่าน Doc กันก่อนได้เลยที่
Ref: https://kotlinlang.org/docs/reference/coroutines