(五十五)iOS多线程之GCD
GCD的全稱為Grand Central Dispatch,翻譯為大中央調度,是Apple開發的一個多線程編程解決方法。
進程和線程的概念:
正在進行中的程序被稱為進程,負責程序運行的內存分配,每一個進程都有自己獨立的虛擬內存空間。
線程是進程中一個獨立的執行路徑,即主線程,主線程有1M的棧區,對于耗時的執行路徑,可以放在子線程(512K棧區)中執行。
Tip:新建線程會消耗內存空間和CPU事件,線程太多會降低系統的運行性能,多線程是通過CPU時分復用實現的。
Tip:多線程是為了并發執行多項任務,不會提高單個算法本身的執行效率。
iOS中三種多線程技術:
1.NSThread
建立一個線程方便,但是管理多個線程非常困難,但是NSThread的currentThread方法可以跟蹤任務所在的線程。
2.GCD Grand Central Dispatch(基于C語言的底層API),使用block來定義任務,推薦使用。
3.NSOperation/NSOperationQueue 使用GCD的一套OC API,提供了一些GCD中不易實現的特性。
Tip:直接使用GCD更好一些。
GCD的核心思想是把操作(block定義任務)放入隊列中,隊列的特點是FIFO(先進先出),出隊時操作被分配到CPU上進行處理。
Tip:隊列不是線程,也不表示對應的CPU,例如雙核CPU,誰空閑分配給誰,出隊時分配到哪個CPU是不需要被關心的。
Tip:GCD的函數都是以dispatch開頭的,dispatch的含義是分派、調度。
Tip:NSThread的currentThread得到的是name和num字典,其中num=1表示主線程。
【進程同步和異步的概念】
進程同步:一個操作沒有完成則不返回,必須一件一件的做事情,一件事情返回了才能做下一件事情。
進程異步:多個操作交替進行,操作的返回時機不確定。
【串、并行隊列】
Tip:同步為sync,異步為async
1.串行隊列的異步任務:使用一個子線程依次執行。
應用:串行隊列中的異步任務會依次執行,例如先下載圖片,然后處理,兩個任務有明確的先后順序,順序是確定的。
/*** 串行隊列*/ - (void)gcdDemo1{dispatch_queue_t q = dispatch_queue_create("queue<1>", DISPATCH_QUEUE_SERIAL);for (int i = 0; i < 3; i++) {dispatch_async(q, ^{NSLog(@"%@ i = %d",[NSThread currentThread],i); //跟蹤當前線程});} }打印串行隊列的輸出發現,i的值是從0到2分別輸出的: 2015-02-16 17:28:11.559 多線程初步[1493:119215] <NSThread: 0x7986cbb0>{number = 2, name = (null)} i = 0 2015-02-16 17:28:11.559 多線程初步[1493:119215] <NSThread: 0x7986cbb0>{number = 2, name = (null)} i = 1 2015-02-16 17:28:11.559 多線程初步[1493:119215] <NSThread: 0x7986cbb0>{number = 2, name = (null)} i = 22.并行隊列的異步任務:使用多個子線程無序執行,一般任務較少時幾個任務就開幾個線程,較多時則開部分線程。
應用:一系列的異步任務沒有先后順序。
/*** 并行隊列*/ - (void)gcdDemo2{dispatch_queue_t q = dispatch_queue_create("queue<2>", DISPATCH_QUEUE_CONCURRENT);for (int i = 0; i < 3; i++) {dispatch_async(q, ^{NSLog(@"%@ i = %d",[NSThread currentThread],i); //跟蹤當前線程});}}打印輸出,發現i的值是隨機排列的: 2015-02-16 17:28:55.084 多線程初步[1521:119972] <NSThread: 0x796347d0>{number = 2, name = (null)} i = 2 2015-02-16 17:28:55.084 多線程初步[1521:119975] <NSThread: 0x79956380>{number = 3, name = (null)} i = 0 2015-02-16 17:28:55.084 多線程初步[1521:119973] <NSThread: 0x796a2ba0>{number = 4, name = (null)} i = 13.串行隊列的同步任務:只使用主線程順序執行,用處較少。 /*** 串行隊列的同步任務*/ - (void)gcdDemo12{dispatch_queue_t q = dispatch_queue_create("queue<1>", DISPATCH_QUEUE_SERIAL);for (int i = 0; i < 3; i++) {dispatch_sync(q, ^{NSLog(@"%@ i = %d",[NSThread currentThread],i); //跟蹤當前線程});} }2015-02-16 17:33:12.938 多線程初步[1574:121669] <NSThread: 0x7a25f5a0>{number = 1, name = main} i = 0 2015-02-16 17:33:12.938 多線程初步[1574:121669] <NSThread: 0x7a25f5a0>{number = 1, name = main} i = 1 2015-02-16 17:33:12.938 多線程初步[1574:121669] <NSThread: 0x7a25f5a0>{number = 1, name = main} i = 2
4. 并行隊列的同步任務:只使用主線程依次執行。
Tip:串行隊列異步任務的用處是最大的,既可以異步,又可以順序執行。
Tip:如果先向隊列中加入異步任務,再加入同步任務,同步任務會穿插在異步任務中運行。
Tip:并行隊列難以控制執行順序與最大并發數,容易出錯。
5.線程名字的作用:打了斷點后,可以在左側看到線程名稱。
Tip:通過點擊CPU的運行狀態還可以得到每個線程的CPU占用情況。
6.非ARC開發時,不要忘記寫dispatch_release(q);
【全局隊列】
Apple提供的,供所有App共同使用,它是一種特殊的并行隊列。
使用dispatch_get_global_queue獲取,第一個參數為優先級,通過右側的提示輸入即可,第二個是供以后使用的,傳入0即可。
與并行隊列的區別:不需要創建,名稱以com.apple開頭。
缺點:調試時無法得到準確隊列的名稱。
【主線程隊列】
注意:iOS只能在主線程上更新UI,因此與UI更新有關的操作應該在主線程執行,它是一種特殊的串行隊列。
使用dispatch_get_main_queue()函數獲取。
與串行隊列的區別:不需要創建,名稱以com.apple開頭。
【進程阻塞】
注意主線程是一直工作的,除非將程序殺掉,否則主線程的工作永遠不會結束。
由于同步任務要等待前面的任務,因此在主線程中加入同步任務,會引起進程阻塞。
Tip:主線程中只能添加異步任務。
【小結】
1.并發編程對多線程編程進行了封裝,不需要關心線程的創建與回收,是為了讓程序員從復雜的線程控制中解脫出來,只需要面對隊列和任務即可。
2.注意隊列的優先級永遠寫DISPATCH_QUEUE_PRIORITY_DEFAULT,優先級出錯時會造成優先級反轉,低優先級的線程可能會阻塞高優先級的線程,為了保險起見,應該使用串行隊列的異步任務。
3.同步任務嵌套同步任務,會引發阻塞,原因在于,第一個任務執行完畢的條件是第二個任務執行完畢,而第二個任務執行完畢的條件是第一個任務執行完畢,因此二者相互等待,無法結束。
4.GCD隊列有5個優先級,優先級從高到底分別為Main->High->Default->Low->Background,后面四級都放入GCD線程池中,最高級的即為主線程。
轉載于:https://www.cnblogs.com/aiwz/p/6154195.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的(五十五)iOS多线程之GCD的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用MATLAB进行二次曲线方程的正交变
- 下一篇: Bellman-ford算法图解