---
# System prepended metadata

title: '[影片筆記] [扔物线](https://www.youtube.com/@rengwuxian)：協程相關教學'
tags: [Concurrency, Kotlin]

---

###### tags: `Concurrency` `Kotlin`
{%hackmd BPS70ijYRAKtBg90J9y3_Q %}
# [影片筆記] [扔物线](https://www.youtube.com/@rengwuxian)：協程相關教學
[TOC]

## [Kotlin 的协程「用力瞥一眼」](https://www.youtube.com/watch?v=LKsGkEsEE7w)
:::info
:information_source: **協程的底層實現還是執行緒池，畢竟如果真的有這麼神奇，Java 這些年難道都不知道？**
:::

協程其實就是 Kotlin 提供的執行緒 API：它可以

- 讓我們以看似同步的語法寫出非同步的程式碼，而不需要過度關心執行緒本身。
- 將多層的回呼 (Callback) 函式抹平為單層的非同步程式碼，這是一個「質變」的改進。

在回呼函式中，非同步這件事是很難做到的，故開發者會妥協而將程式碼同步化，而這便犧牲了執行效率。有了協程，非同步變得輕鬆寫意：執行緒想怎麼切就怎麼切，我們只需要合併最後的結果。

舉例來說，
```kotlin=
launch(Dispatchers.IO) {
    // ...
    launch(Dispatchers.Main) {
        // ...
        launch(Dispatchers.IO) {
            // ...
            launch(Dispatchers.Main) {
                // ...
```
的回呼形式現在可以直接攤平為
```kotlin=
launch(Dispachers.IO) {
    // ...
    withContext(Dispatchers.Main) { // ...
    // ...
    WithContext(Dispatchers.Main) { // ...
```

## [Kotlin 协程的挂起好神奇好难懂？今天我把它的皮给扒了](https://www.youtube.com/watch?v=mDtXcEuOXvk)
所謂的 `suspend` 就是指協程 (也就是 `launch` 或 `async` 裡的程式碼) 被暫停了。但是與其譯作暫停，不如用「脫離」這個字眼會更好：協程只是從目前的執行緒脫離，而並非是真的停止了。

因此我們有兩件事需要釐清：

- 如何處理閒置的執行緒？
- 脫離後的協程會到哪裡？

第一個問題的答案就跟執行緒池的處理一樣 (畢竟本質一模一樣)，這個執行緒要嘛做其它事，要嘛被回收掉；而脫離的協程會在暫停函式指定的執行緒中執行，待函式結束後再依照調度器的種類，決定是否切回原執行緒：Kotlin 把「切回來」這件事叫做 Resume。

而協程也並不是一進入另一個暫停函式時，就從原執行緒脫離：這件事是遇到 `withContext()` 才發生的。創建暫停函式的目的與其它的函式都一樣：降低程式碼的重複性、增加程式碼的可讀性。

總結來說，創造 `suspend` 這個關鍵字並不是為了直接處理協程，而是要讓函式創建者提醒、警示調用者：現在要使用的函式很花時間，所以必須放在後臺執行，因此你需要在協程中呼叫這個函式。

## [到底什么是「非阻塞式」挂起？协程真的比线程更轻量级吗？](https://www.youtube.com/watch?v=NnLQ9zvrcCo)
所謂「非阻塞式」就是「不卡執行緒」的意思：所有的程式碼在本質上都是阻塞式的，只是它們通常都不耗時，導致我們察覺不出來。另外，協程本質上就是一個切執行緒的 API，沒什麼特別的魔法。