一,進程和線程
1,進程
定義:
- 進程是指在系統中正在運行的一個應用程序
- 每個進程之間是獨立的,每個進程均運行在其專有的且受保護的內存
- 進程是系統進行資源分配和調度的一個獨立單位
補充:iOS系統是相對封閉的系統,App在各自的沙盒中運行,每個APP都只能讀取系統為該應用程序創建的文件夾AppData下的內容,不能隨意跨域自己的沙盒去訪問別的App沙盒中的內容。也就是說iOS是單線程的,一個App就是一個進程。
特點:
- 獨立性:是系統獨立存在的實體,擁有自己獨立的資源,有自己私有的地址空間。在沒有經過進程本身的允許的情況下,一個用戶的進程不可以直接訪問其他進程的地址空間。
- 動態性:程序是一個靜態的指令集合,而進程是一個正在系統中活動的指令集合,進程中加入了時間的概念。進程具有自己的生命周期和不同的狀態,這些都是程序不具備的
- 并發性:多線程可以在單個處理器上并發執行,多個進程之間不會相互影響
2,線程
定義:
- 線程是進程的基本執行單位,一個進程的所有任務都在線程中執行
- 進程要想執行任務,至少要有一個線程
- 程序啟動會默認開啟一條線程,這條線程被稱為主線程和UI線程
3,進程和線程的關系
- 地址空間:同一進程的線程共享本進程的地址空間,而進程之間則是獨立的地址空間。
- 資源擁有:同一進程內的線程共享本進程的資源如內存,I/O,CPU等,但是進程之間的資源是獨立的。
- 進程切換時,消耗的資源大,效率高。所以涉及到頻繁的切換時,使用線程要好于進程。同樣如果要求同時進行并且又要共享某些變量的并發操作,只能用線程不能用進程
- 執行過程:每個獨立的進程有一個程序運行的入口、順序執行序列和程序入口。但是線程不能獨立執行,必須依存在應用程序中,由程序提供多個線程執行控制。
- 線程是處理器調度的基本單位,但是進程不是
4,任務
- 通俗的說任務就是一件事情或一段代碼,線程其實就是去執行這個時期
5,隊列
- 隊列是先進先出的線性表。裝載線程任務的隊形結構。隊列只允許新數據在后端進行添加。
隊列的類型
- 并發隊列:線程執行可以同時一起執行,不需要上一個執行完,才能執行下一個的
- 串行隊列:線程執行只能依次逐一先后有序的執行,等待上一個執行完,再執行下一個
- 主隊列:綁定主線程,所有任務都在主線程執行,有經過特殊處理的串行隊列
- 全局隊列:系統提供的并發隊列
6,同步和異步
- 同步sync:只能在當前線程按先后順序依次執行任務,不具備開啟新線程的能力
- 異步async:在新的線程執行任務,具備開啟新線程的能力
二,多進程和多線程
- 在早期單核CPU
如何理解多進程?在早期單核CPU時代,由于CPU執行代碼都是順序執行的,那么單核CPU如何執行多任務?
比如說一邊用瀏覽器上網,一邊聽音樂,一邊寫代碼
這里用到時間片輪換調度
:簡單就是把一個處理器劃分為若干個段的時間片,每個進程會被操作系統分配一個時間片(即每次被CPU選中來執行當前進程所用的時間),每個時間片依次輪流地執行處理各個應用程序,時間一到,無論進程是否運行結束,操作系統就會強制將CPU這個資源轉到另一個進程去執行,由于每個時間片很短,對于每個程序,就好像為自己單獨服務,從而達到多個程序同時進行的效果。
如何理解多線程?
在一個程序中,以QQ聊天為例,當QQ這個進程被CPU分配時間處理時,這時我們需要處理聊天還是處理界面的刷新。如果處理了聊天,界面就不會刷新,看起來界面就卡死了。同樣上上面一樣,每次 CPU 執行100ms,其中30ms用于處理聊天,40ms用于處理傳文件,剩余的30ms用于處理界面刷新,這樣快速切換處理。就可以達到多線程的效果。
- 在當前的多核CPU
多核CPU擁有多個物理核心,每個物理核心可以同時執行一個進程(線程)或多個進程(線程)。這意味著在多核CPU下,多個進程(線程)可以正真并行執行,每個線程在各自的核心上獨立運行。
在多核CPU的情況下,也可能會出現一個CPU核心處理多個進程(線程)的情況。
每個線程在自己的核心上獨立執行,互不干擾,可以充分利用CPU的并行處理能力。這種并行執行可以提高系統的響應性和吞吐量。
區別:
在多核CPU下,多線程的并發編程相對復雜,需要考慮線程間的同步、互斥和數據共享等問題。由于多個線程可以同時訪問和修改共享數據,可能會出現競態條件和數據不一致的問題,需要使用同步機制(如鎖、信號量等)來實現線程安全。
而在單核CPU下,由于只有一個線程在執行,不存在多個線程同時訪問共享數據的問題,因此并發編程的復雜性相對較低。
三,多線程的生命周期
- 新建:實例化線程對象
- 就緒:向線程對象發送start消息,線程對象被加入可調度線程池等待CPU調度。
- 運行:CPU負責調度可調度線程池中線程的執行,線程執行完成之前,狀態可能會在就緒和運行之間來回切換。就緒和執行之間的狀態變化由CPU負責。
- 阻塞:當滿足某個預定條件時,可以使用休眠或鎖,阻塞線程執行,所謂
阻塞狀態
是正在運行的線程沒有運行結束,暫時讓出CPU,這時其他處于就緒狀態的線程就可以獲得CPU時間,進入運行狀態。 - 死亡:正常死亡,線程執行完畢。非正常死亡,當滿足某個條件后,在線程內部終止執行/在主線程終止線程對象
線程池
線程池是一種“池化”的線程使用模式。線程的創建,銷毀,調度都有一定的開銷,通過預先創建一定數量的線程,讓這些線程處于就緒狀態來提高系統響應速度,在線程使用完成后歸還到線程池達到重復利用的目的,從而降低系統資源的消耗,提高響應速度,增加了線程的可管理性。
四,多線程的四種使用方法
我們一般使用比較多的是 GCD,因為開發者只需要告訴 GCD 想要執行什么任務,不需要編寫任何線程管理代碼,但這也是 GCD 的不夠靈活的地方,我們無法監控線程的各個狀態,這也是很多大框架中使用 NSOperation
的原因,NSOperation 相比 GCD 更加靈活,開發者可以通過 KVO
監測 Operation
的狀態,自定義 NSOperation 等。
五,多線程的意義
- 某個操作可能會陷入長時間等待,等待的線程會進入睡眠狀態,無法繼續執行。多線程執行可以有效利用等待時間進行線程切換。如等待網絡響應。
- 某個操作可能會消耗大量的時間,如果只有一個線程,程序和用戶之間的交互會被中斷。多線程可以讓一個線程負責交互,另一個線程負責計算。
- 多CPU或多核處理器,本身具備同時執行多個線程的能力,因此單線程程序無法全面發揮計算機的全部計算能力。
- 多線程可以提高程序的效率。多線程同步完成多項任務,不是為了提高運行效率,而是為了提高資源使用效率來提高系統的效率。
多線程的不足:
- 開啟線程需要占用一定的內存空間(默認情況下,每條線程占512kb);如果開啟大量的線程,會占用大量的內存空間,降低程序的性能。
- 線程越多,CPU在調用線程上的開銷就越大(因為要在線程之間切換);
- 多線程編程的程序設計會更加復雜(如線程間的通信、多線程的數據共享等)。