進程
早期的計算機運行程序還是隻能一次運行一個任務,之後進程的出現實現了近似同步的執行效果,其本質上是程序的交替執行。爲了保證進程中的程序能夠正常執行,還會有一些存儲進程狀態的保存集。隨着硬件的發展和多CPU的出現,能夠同時執行的進程數量逐漸增多。這就帶來了一個問題,即用來存儲進程狀態的集合所佔用的資源比一個進程可以執行的資源還要多,相當於整個系統大半的進行都是用來保存進程的狀態。
線程
線程的提出有效的解決了這個問題。進程不再頻繁的切換,而是先執行,遇到阻塞的話暫時不管,繼續執行其他的任務,當其他任務執行完之後再回過頭來看阻塞任務是否執行完。多線程的缺陷在於無法自主控制調度,除開一定會執行的主線程之外,其他線程的執行順序都無法控制,在Java上是由Java虛擬機調度,其他平臺大多是由系統控制。
協程
線程執行過程中發生線程切換的時候會損耗一定的資源,這部分資源用來保存線程的狀態。執行過程中如果發生了磁盤讀寫或網絡請求這樣的IO操作的時候線程的執行會被阻塞,但同時該線程還會持有CPU資源,這就造成了一定了資源浪費。理想的情況是在發送阻塞的時候,該線程主動交出CPU給其他線程使用或者給內部的其他任務。
這種方式其實就是協程的體系。通過提升CPU利用率,減少線程切換,進而提升程序運行效率。
延伸開來協程主要有三個特性:
第一個是可控制,不同於線程協程能做到可被控制的發起子任務;
第二個是輕量級,協程非常小、佔用資源比線程還少,在JVM平臺上它的本質就是一次方法的調用;
第三個是語法糖,目前能夠使用協程的語言都提供了很好的語法糖支持,使多任務或多線程切換不在使用回調語法。
協程很好的解決了兩個問題
耗時任務
主線程安全
android 主線程負責UI和用戶交互,如果主線程任務過多就會阻塞主線程。爲了在主線程避免網絡請求採用CallBack回調,
- suspend —— 掛起當前協程的執行,保存所有局部變量
- resume —— 從被掛起協程掛起的地方繼續執行
Kotlin協程通過掛起和恢復共同工作來替代回調。
Kotlin中每個協程的協程體都實現了這個接口Continuation,協程的本質也就是一次回調,只不過通過語法糖的形式讓它看起來像是順序執行
Kotlin 提供了 Dispatchers 來處理線程調度
通過協程,你可以細粒度的控制線程調度。 withContext
讓你可以控制任意一行代碼運行在什麼線程上,而不用引入回調來獲取結果
爲了避免泄露協程,Kotlin 引入了 structured concurrency(結構化併發)。結構化並集合了語言特性和最佳實踐,遵循這個原則將幫助你追蹤協程中的所有任務。
在 Android 中,我們使用結構化併發可以做三件事:
- 取消不再需要的任務
- 追蹤所有正在進行的任務
- 協程失敗時的錯誤信號
讓我們深入探討這幾點,來看看結構化併發是如何幫助我們避免丟失對協程的追蹤以及任務泄露