---
# System prepended metadata

title: '**逐字稿**'

---

# **逐字稿**

(我們把落落長解釋放這裡好了，投影放presentation那一個，念這個)

**I. MVC v.s. MVVM**

開始先介紹MVC架構和它的優缺點，接著在介紹MVVM。
* M: Model (=data class)
* V: View (=layout的 .xml)
* C: Controller(=Activity/Fragment)

- MVC
將 Model, View 和 Controller 分離讓彼此的職責 (responsibility) 能夠明確的分開，這樣不論是改 M, V 還是 C，都可以確保另外兩層可不用做任何修改，同時這樣的分層也可以加強程式的可測試性 (testability)，View 和 Model 基本上是相關的，但它們並不會有直接的相依關係，而是由 Controller 去決定 Model 產生的資料，然後丟給 View 去做呈現，也就是說，Controller 是 Model 和 View 之間的協調者 (coordinator)，View 和 Model 不能直接溝通，以確保責任的分離。而 Controller 可以只是一個繫結 Model 和 View 的小類別，也可以是大到包含 Workflow, Enterprise Services 或是做為外部系統的 Proxy Services 等的邏輯系統

- MVVM
架構一樣是 M, V 分離，但中間是以 VM (ViewModel) 來串接，這個 ViewModel 比較像是 View 的一個代理程式，它負責直接對 Model 做溝通，而 View 可以透過一些機制 (ex: Events, Two-way Databindings, ...) 來和 ViewModel 溝通以取得資料或將資料拋給 Model 做存取等工作，ViewModel 也可以作為和外部系統的代理程式

- 差別
和 MVC 不同的地方，就是 ViewModel 和 View 的黏合度比較高，因為 View 必須要透過 ViewModel 才可以取得 Model，而 ViewModel 又必須要處理來自 View 的通知訊息，所以雖然職責一樣分明，但是卻不像 MVC 那樣可以擴展到整個系統元件都能用。
- 結論
MVC 架構適合於大型系統，它可以分層且可以在實體層面切割為不同的機器或服務，只要彼此間具有適當的通訊協定即可。
MVVM 架構適合像 XAML 這種與程式碼無關 (code ignorance) 的使用者介面設計，只要 View 中下特定的指令與 ViewModel 串接，就可以享有 ViewModel 溝通的功能，而 ViewModel 只需做一些特別的介面實作，即可平順的和 View 溝通。

什麼是耦合和解耦
作者：longjf126
链接：https://www.zhihu.com/question/271519628/answer/994947868
来源：知乎
著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。

1、你首先得知道，在中文里，【耦合】的原本含意。耦合的耦，在中国古代是指 两人并肩而耕，就是两个人在一起合作使用农具耕地，这是上古农耕时代对农业生产的写实描述，是中古时代以前古中国的田园生活，（中国上古、中古）农具“耒”（犁的前身）是需要两个人一起进行合作，进行联合操作的。【耦，是中国古代生活史、经济史、农业农耕史、农业工具发展史在中国文字上的真实反映。】所以，耦合，从古代农业领域借用到其他领域，在物理学上指两个或两个以上的体系或两种运动形式之间通过各种相互作用而彼此影响，甚至联合起来的现象；耦 同“偶”，通“偶”。然后，在学术上被借用到很多领域，其实就是用以描述 偶数【 2 】以上 多体系的相互作用/彼此影响/互相联合之现象。2、英文单词coupling，用夫妻/两个/一对儿/连接、联接/成双成对/，等等来描述学术上的耦合/耦合性，大致上也能描述，“耦合”现象的中文表述和外文表述其实是大差不差的，但我总觉得欧洲人在词汇拓展上有点贫瘠，有点蛋疼。2020-02-02 最后，我为什么觉得 英文 使用  有 “夫妻”、“两人”、“一对”、“连接”、“几个”、“几名”等含义之“couple”原型单词 所衍生的 英文单词 "coupling"  ，描述 耦合/耦合性 有点蛋疼，有点贫瘠呢？回答：因为 在学术上，耦合 在一起的两个体系（模块、系统）或者几个体系（模块、系统），其实 并不一定就是 “一对”、“成双成对”的关系，也并不一定是类似“夫妻”或“情侣”的关系。中国古代两个人配对在一起联合操作农具“耒”的， 耦 ，有可能是夫妻，有可能是父子，有可能是母子，也可能是兄弟，也可能是 妯娌、姐妹，甚至可能是十户连坐的同村邻居、隔壁邻居、乡里乡亲。在盛行使用奴隶生产的上古，甚至可能是完全没有血缘没有亲缘关系的奴隶、奴婢。所以，真要说哪个更贴切，我个人觉得“耦合”一词更贴切现代学术各个学科所描述的 各种 耦合 现象——当然，前提是你得对中国古代农业农耕历史、古代农具发展历史、中国古代文化基本有所了解，否则你无法很好理解这个词汇用来描述各种耦合现象的精妙贴切之处。
* 什麼是業務邏輯
* 為什麼MVVM架構變成主流 -> 從Android Jetpack被發表後->Android Jetpack是什麼?優點?
1. 輕鬆管理應用程式的生命周期
1. 構建可觀察的數據對象，以便在基礎資料庫更改時通知視圖
1. 存儲在應用程式輪換中未銷毀的UI相關數據，在介面重建後恢複數據
1. 輕鬆的實現SQLite資料庫
1. 系統自動調度後台任務的執行，優化使用性能

基本來說就可以把 App 分成三大模塊
各個模塊之間的溝通都是抽象的，讓彼此之間的耦合度降低（decoupling），讓各個元件專注在自己的業務上，但是調整的過程又能夠最小限度的影響到相依賴的元件。也就是關注點分離的概念（Separation of concerns）

>**關注點分離 **
>關注點分離（Separation of concerns，SoC）是對只與「特定概念、目標」（關注點）相關聯的軟體組成部分進行「標識、封裝和操縱」的能力，即標識、封裝和操縱關注點的能力。是處理複雜性的一個原則。關注點分離，就是將交錯著各種目的的複雜程式碼，依程式碼的概念、目的，進行分類、篩檢、整理。讓高複雜性程式碼切割、轉換為簡潔易懂的單純性程式碼。其好處是將特定領域的程式碼與商業邏輯切割，使其獨立處理。進一步的，讓程式碼本身的目的單純化。
同時，關注點分離，不僅讓協作程式開發的可能性大大的提升，也讓軟體的維持與改版成本變的更低。

>  一、耦合(coupling)
> 
> 1、耦合是指兩個或兩個以上的體系或兩種運動形式間通過相互作用而彼此影響以至聯合起來的現象。
> 
> 2、在軟體工程中，物件之間的耦合度就是物件之間的依賴性。物件之間的耦合越高，維護成本越高，因此物件的設計應使類和構件之間的耦合最小。
> 
> 3、分類：有軟硬體之間的耦合，還有軟體各模組之間的耦合。耦合性是程式結構中各個模組之間相互關聯的度量。它取決於各個模組之間的介面的複雜程度、呼叫模組的方式以及哪些資訊通過介面。
> 
> 二、解耦(decoupling)
> 
> 1、解耦，字面意思就是解除耦合關係。
> 
> 2、在軟體工程中，降低耦合度即可以理解為解耦，模組間有依賴關係必然存在耦合，理論上的絕對零耦合是做不到的，但可以通過一些現有的方法將耦合度降至最低。
> 
> 3、設計的核心思想：儘可能減少程式碼耦合，如果發現程式碼耦合，就要採取解耦技術。讓資料模型，業務邏輯和檢視顯示三層之間彼此降低耦合，把關聯依賴降到最低，而不至於牽一髮而動全身。原則就是A功能的程式碼不要寫在B的功能程式碼中，如果兩者之間需要互動，可以通過介面，通過訊息，甚至可以引入框架，但總之就是不要直接交叉寫。
> 
> 4、觀察者模式：觀察者模式存在的意義就是「解耦」，它使觀察者和被觀察者的邏輯不再攪在一起，而是彼此獨立、互不依賴。比如網易新聞的夜間模式，當用戶切換成夜間模式之後，被觀察者會通知所有的觀察者「設定改變了，大家快蒙上遮罩吧」。QQ訊息推送來了之後，既要在通知欄上彈個推送，又要在桌面上標個小紅點，也是觀察者與被觀察者的巧妙配合。

> 什麼是商業邏輯？
> 商業是指一個實體單元向另一個實體單元提供的服務。
> 邏輯是指根據已有的資訊推出合理的結論的規律。
> 
> 業務邏輯的內容包括四個部分：
> 
> 領域實體：定義了業務中的物件，物件有屬性和行為；
> 商業規則：定義了需要完成一個動作，必須滿足的條件；
> 資料完整性：某些資料不可少；
> 工作流：定義了領域實體之間的互動關係。
> 
> 以大川網購褲子為例
> 
> 領域實體：大川、資金賬戶、訂單、褲子、發貨單
> 商業規則：大川點選購買就會生成訂單，但必須付了錢，才會發貨，生成發貨單。
> 資料完整性：淘寶網下訂單必須登入賬號，沒有賬號就不能成功購買。
> 工作流：搜尋褲子-找到合意褲子-下單購買-付賬-收貨。
> 業務邏輯：搜尋“褲子”-找到合意褲子-下單-必須登入賬號-結算-付賬-收貨。
> 
> 商業邏輯層負責系統領域業務的處理，負責邏輯性資料的生成、處理及轉換。對所輸入的邏輯性資料的正確性及有效性負責，但對輸出的邏輯性數 據及使用者性資料的正確性不負責，對資料的呈現樣式不負責。



- MVC (Model / View / Controller)
MVC架構中，把程式分成了三個層級：

M：Model － 負責處理與資料相關的事情，包括取得資料、儲存資料等等。
V：View － 如字面上所示，就是與介面相關的東西。
C：Controller － 介於View及Model之間的橋樑，接收來自View的事件，去操控Model的資料。
![](https://i.imgur.com/TL8YNS1.png)



- Android 中的 MVC
在Android的世界中可以將Layout的XML視為View，
database視為Model，而Activity或Fragment則是Controller。

View上元件的操控通常會寫在Activity或Fragment當中，導致Activity或Fragment需同時負責View及Controller的事情(通知View資料更新、Data邏輯運算)，當介面越複雜、要處理的邏輯越多時，Activity或Fragment的程式碼就會變得又臭又長。
好處在把 View 與 Model 切開，各司其職方便管理。


- MVVM (Model / View / ViewModel)
MVVM 當中的 ViewModel，主要是負責接收來自 View 的事件，去取得 Model 的 Data 並處理 Data，最主要的不同是，View的更新是由Model中的資料來驅動的，當資料有所更動的時候，UI會自動做相對應的呈現。

![](https://i.imgur.com/RpLfktW.png)


- Android 中的 MVVM
在MVVM中最重要的特點就是資料變成很重要的一項因素，因為事件的觸發會變成是由資料的變動而觸發的 也就是在 ViewModel 中使用 LiveData 。在ViewModel中，則不需要知道View是誰，而需要被更動的View只要去監控( observe )資料是否變動了，有變動則更新View。
為了自動更新View，會配合使用Databinding，把觀察到改變的LiveData連結到View上做自動更新。
這樣的好處就是ViewModel只需要好好的負責與Data相關的事情，在ViewModel中就不需要寫一堆控制View的程式碼，只需要專心管理流程，而Activity跟Fragment則專心操控介面及生命流程。

在MVC中，當資料發生變動時需要自己去控制元件的變化，也就是在Model當中必須要知道他的View是誰然後再去主動更新他。

* Activity和Fragment負責產品與用戶的交互
* ViewModel作為數據的存儲和驅動
* Resposity負責調度數據的獲取
* Room儲存本地序列化的數據
* Retrofit獲取遠程數據的數據



---
:::info
II. Activity and Fragment Lifecycle
:::

- Activity 是甚麼?
  1. Activity 用來顯示 View，User 可以跟他互動操作。
  2. 一個App可以有多个Activity。

- 生命週期 ? 


---
  Activity是一個App的活動，他在螢幕上提供了一個區域，允許用戶在上面做交互性的操作， 比如打電話，照相，發送郵件，或者顯示一個地圖！ Activity可以理解成一個繪製用戶界面的 View， 而這個View可以填滿整個螢幕，也可能比螢幕小或者浮動在其他View的上方！
  
---
  既然是Activity是一個活動，從他開始被系統創建到結束回收的過程，就稱為他的生命週期。
  Android為了管理Activity，就在他生命周期內定義了不同的state，方便開發者針對在生命週期內某些state做一些想要的操作。
  
---
<備用>
所謂生命週期，其實就是 Android  系統用來管理資源分配的一種機制，當記憶體的資源不足時，系統會自動依照優先等級進行回收，因此，透過了解 Activity 的生命週期，我們可以更明確的利用已知的狀態改變機制，在特定的情況下去控管一些所需的變數，進而達到我們要的目的。

---

- Activity 生命週期：
  - onCreate
  此週期在開啟應用程式時會是第一個進入的流程 ,並且在應用程式週期中只會執行一次 ,主要用來宣告物件及設定監聽事件。在這個階段，初始化它的物件。
  
  - onStart((我們看的到它了!!!!)visible 
  負責將 activity 頁面可視化 ,並將 UI 物件初始化以便讓使用者互動。
  
  - onResume (使用者可以跟他互動了!!!!跟他互動了!!!!)
  應用程式處於持續執行中，且一直與使用者互動著，直到使用者的切換到另一個activity或開啟其他應用程式
  
  - onPause(使用者看的到 但是無法操作它)
  當運行的應用程式跳出了對話框 ,activity會進入背景(未完全進入) ,即進入onPause狀態 ,對話框消失後 ,若沒有跳轉到其他的activity則會呼叫onResume 繼續當前的activity。
  通常用在釋放系統資源(ex.相機、GPS功能)
  - onStop (看不見了!)
  當activity完全進入背景, 即進入onStop狀態
  
  - onDestroy(滑掉 整個關閉)
  使用者終止應用程式就會觸發這個流程 ,若系統資源在極度缺乏的情況下也可能直接終止於onStop、onPause狀態的應用程式

---
- Fragment 是甚麼?
  - 為了大螢幕的平板電腦，fragment 可以小型的Activity，又稱Activity片段，方便模組化管理。
  - 一個Activity內可以同時顯示一個或多個 fragment。
  - Fragment並不能單獨使用，他需要依附在 Activity 中使用。

Fragment是Android3.0後引入的一個新的API，他出現的初衷是為了適應大屏幕的平板電腦， 當然現在他仍然是平板APP UI設計的寵兒，而且我們普通手機開發也會加入這個Fragment， 我們可以把他看成一個小型的Activity，又稱Activity片段！想想，如果一個很大的界面，我們 就一個佈局，寫起界面來會有多麻煩，而且如果組件多的話是管理起來也很麻煩！而使用Fragment 我們可以把屏幕劃分成幾塊，然後進行分組，進行一個模塊化的管理！從而可以更加方便的在 運行過程中動態地更新Activity的用戶界面！另外Fragment並不能單獨使用，他需要嵌套在Activity 中使用，儘管他擁有自己的生命週期，但是還是會受到宿主Activity的生命週期的影響，比如Activity 被destory銷毀了，他也會跟著銷毀！

---

- fragment生命週期

  fragment生命週期與Activity一樣有著
  >onStart  <---> onStop   , fragment is visible or not.
  >onResume <---> onPause  , fragment is focus or not focus.

  
  
  除此之外，因為是 fragment 顯示在 activity 上，所以生命週期多了以下幾種狀態。
  - onAttach()  (通知fragment要被加進來了)
    >Called when the fragment has been associated with the activity (the Activity is passed in here).
  - onCreate()   (初始化) 
  - onCreateView()  (畫畫面)
    >Called to create the view hierarchy associated with the fragment.
  - onActivityCreated() (檢查Activity有沒有被創建了)
    >Called when the activity's onCreate() method has returned.
  - onDestroyView() (頁面替換為另一個 fragment)
    >Called when the view hierarchy associated with the fragment is being removed.
    >這時fragment仍然活著(所有狀態和 Data 被系統保持著),然而它對用戶不再可見，並且如果activity被幹掉，他也會被幹掉。
  - onDetach() (從Activity被移除)
    >Called when the fragment is being disassociated from the activity.

![](https://i.imgur.com/2iVzLAt.png)


我們會有Lifecycle是因為要做資源控管，不要不分青紅皂白在資源不足時關閉我們的app!

- 《系統回收資源的優先等級》 :dagger_knife: 

  - 第一優先 : 空行程 (Empty Process)
空行程指的是獨立的 Activity，當一個 Activity 在當下沒有與任何其他 Activity 關聯時，即稱為空行程。

  - 第二優先 : 背景行為 (Background Activity)
處於 onStop() 狀態下的 Activity 即稱為 Background Activity。
  - 第三優先 : 伺服器行程 (Service Process)
Service Process 即是於程式背景執行，不帶有 UI 介面的一個類別。
  - 第四優先 : 可視行為 (Visible Activity)
處於 onPause() 狀態下的 Activity 即稱為 Visible Activity。
  - 第五優先 : 當下行為 (In process Activity)
當記憶體嚴重不足，最後會被回收的，就是當下正在執行的 Activity。



備註:
LifecycleOwner

```kotlin=
binding.lifecycleOwner = this
```
fragment透過observe觀察liveData的狀態
xml再透過lifecycleOwner觀察observer的狀態
https://developer.android.com/topic/libraries/architecture/livedata

---
:::info
III. ANR
:::

![](https://i.imgur.com/qPCTr2w.png)
**ANR Definition**
什麼是ANR?
ANR是Application Not Responding的縮寫(應用程式無響應)，是Android的一種自我保護措施。在Android中，應用程式響應由Activity Manager和Window Manager系統服務進行監視的。當App的主線程被卡頓長達5s沒反應的時候，Android系統就會彈出提示(trigger ANR error)，彈出一個視窗讓用戶手動選擇繼續等待還是強制關閉這個App。


**ANR產生的原因**

在Android系統中，APP 通常運行在一個UI Thread或者叫Main Thread裡。Android中只有一個MainThread 和 Main Message Queue。
MainThread主要用於UI的繪製、事件響應，監聽與接收事件處理等功能。
Main Message Queue 主要存放用戶要處理消息的隊列。
當主線程(MainThread)從消息隊列(Main Message Queue)中取消息(Message)後，儘快分發下去，一旦某條消息分發超時，則ANR可能發生。

deadlock(你等他、他等你)
兩個子線程都在等對方的資料

**ANR的類型**(常見ANR的三種類型)
  1. Key Dispatch Timeout(按鍵響應分發超時)

>   Activity在5秒鐘之內無法回應View事件或鍵盤輸入事件就會產生ANR。

  2. Broadcast Timeout(廣播超時)
  
  媽媽(別的app)叫小孩起床 如果10秒沒有反應 
> BroadcastReceiver在10秒鐘之內未執行完成就會產生ANR。
> 
> 
> 什麼是BroadcastReceiver? 
> 它是『廣播接收器』，它是一種系統級的全範圍通知，而不是針對單一位置。這樣的好處是，我們不必明確指出需要回應這個廣播的位置，就可以驅動需要回應此廣播的事件，舉個簡單的例子，這就好比在學校裡，當訓導主任廣播尋找王小明時，訓導主任只需要告知要找的是幾年幾班的王小明(不用知道他在哪裡)，儘管全校的同學都會聽到這則廣播，但會去訓導處報到的，就只有王小明，在 android 中，我們時常需要利用此一機制，讓程式能在任何時候，對於不同的廣播訊息做出正確的反饋。

  3. ServiceTimeout (服務超時)
    
> Service各個生命週期在20秒鐘之內沒有執行完成就會產生ANR。
  例如在onCreate()中寫了太多要執行的東西，導致他在20s內無法執行結束跳往下一個state就會trigger。

  

**How to debug 如何分析解決ANR**

* 使用 Strict Mode

* Enable background ANR dialogs
可於手機開發人員選項開啟 Show all ANRS
* 使用 Traceview https://www.itread01.com/articles/1485373131.html

**How to avoid 如何避免ANR(增強響應靈敏性)**


dead lock??https://ithelp.ithome.com.tw/articles/10229583
lock contention??


---

IV. Lambda Expressions
kotlin 的 lambda 本身就是一個object ,所以可以把他當成參數傳遞
https://www.youtube.com/watch?v=S15iwhvBokI&list=PLsxOieREJewd9dy7MJMxgp7uddA4R9eOe&index=5&ab_channel=KaiZhu

https://kaixue.io/kotlin-lambda/
---
---

V. Kotlin Coroutines
- 什麼是Coroutines
Coroutine是用於幫助處理非同步需求的機制 ,即線程框架 ,
最典型的特色，允許 method 被暫停( suspended)執行之後再回復執行，而暫停執行的 method 狀態允許被保留，復原後再以暫停時的狀態繼續執行。
舉例來說我在 main thread 執行到 function A 需要等 IO thread 耗時處理的結果，那我先暫停 function A， 協調讓出 main thread 讓 main thread 去執行其他的事情，等到 IO thread 的耗時處理結束後得到結果後再回復 function A 繼續執行，並得到我要的結果，這就是 Coroutines 的概念。
- 為什麼要使用？
    剛剛有提到 我暫停了需要等待結果的function ,為了讓main thread 可以去執行其他的事情 ,那如果我沒有暫停那個須等候結果的function的話 ,main thread 就會卡住沒有辦法進行其他的操作 ,
    那在等待 function A 的時候 main thread 啥事都不能做，只能 idle 在那邊動也不動。
    這如果是在 Android main thread 上，這樣的行為會讓畫面 freeze ，時間稍微長一點就會 ANR 被 系統 當作異常進行排除了。
- 如何使用?
  - CoroutineScope 
  指的是協程作用的範圍，可以是作用在 Main thread 或是 IO thread 上，依情況而定。 
    - GlobalScope : 繼承於ConroutineScope ,作用在整個 Application 上，伴隨 APP 的生命週期。這代表此協程的生命周期只受整個應用程式的生命周期限制。使用他可以避免 Coroutines 被過早結束。
  - Suspend
    Coroutine scope裡
    表示這個 function 是可以被 "暫停" 的。suspend function 可以被其他的 suspend function 調用，但是不能被一般的 function 調用，因此 coroutines 提供了幾個 coroutine builders
    - runblock：
      啟動一個協程並 block 此線程直到協程完成
      它的目的是確任流程的串聯而非並聯
    - launch：
  在不阻塞當前線程的情況下啟動一個協程並返回一個 Job
    - withContext：
  不會建立新的協程，而是在指定的協程上運行
    - async：
  在不阻塞當前線程的情況下啟動一個協程並返回一個叫 Defered 的 class，需要與 await 一起使用。

  Defered 使一個協程可以 suspend 並等待另一個協程產生結果，直到另一個協程完成。
  - Job 
指的是用來控制 Coroutines 的類，常見的有以下幾種控制方式：
    - cancel()：取消 Coroutines
    - join()：等待 Job 執行結束
    - cancelAndJoin()：其實就是上面兩者的合併方法
    - isActive：確認 Coroutines 是否執行中
    
  
  - Dispatchers
是 Kotlin Coroutines 預先準備好供開發者使用的CoroutineContext
    - Dispatchers.Default：使用的 Thread 取決於調用時當下的 Thread，最大並行的協程數量則依據系統的 cpu 核心數量，最少為兩個
    - Dispatchers.Main：即跑在 Main Thread 上
    - Dispatchers.IO：會開一條 Worked Thread，並在上面執行，適合用在 IO 之類的耗時操作
    - Dispatchers.Unconfined：會跑在開啟時當下的 Thread ，但是一旦在 suspend 後再被恢復，可能會執行在其他線程上
- 如果不用Coroutines 怎麼用元件的方式實現功能
    - Callback (Lambda)
  ```kotlin
    fun getTokenAsync(action: (Token) -> Unit) {
        ......
    }

    fun verifyAsync(
        token: Token,
        userName: String,
        action: (Boolean) -> Unit
    ) {
        ......
    }

    fun requestAndSaveUserDataAsync(
        userName: String, 
        result: (Result) -> Unit
    ) {
        ......
    }

    ......

    fun login(userName: String) {
        getTokenAsync { token ->
            verifyAsync(token, userName) { verifyResult ->
                requestAndSaveUserDataAsync(userName) { result ->
                    showLoginSuccess("Success")
                }
            }
        }
    }
  ```
    - RxJava
  https://blog.csdn.net/xiangzhihong8/article/details/52075392
- 要被問的問題
  跟一般的線程有甚麼區別?
  coroutines可以等耗時工作得到結果時候自動切回該線程並完成操作 ,但一般線程還需要做額外的處置 ,所以coroutines只是thread的加強版
  
  他跟我說的 :point_down: 
  https://www.youtube.com/watch?v=NnLQ9zvrcCo


https://juejin.im/user/2524134386185736
https://juejin.im/post/6844903949686800392#heading-4

process、thread、coroutines 關係
https://blog.kennycoder.io/2020/05/16/%E9%80%B2%E7%A8%8B-Process-%E3%80%81%E7%B7%9A%E7%A8%8B-Thread-%E3%80%81%E5%8D%94%E7%A8%8B-Coroutine-%E7%9A%84%E6%A6%82%E5%BF%B5%E8%AC%9B%E8%A7%A3/
多線程用法
https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/732413/