iOS開發之多線程

來源:互聯網
上載者:User

標籤:

1多線程概念

進程

進行中中的程式被稱為進程,負責程式啟動並執行記憶體配置。每一個進程都有自己獨立的虛擬記憶體空間。 

線程

線程是進程中一個獨立的執行路徑(控制單元)

一個進程中至少包含一條線程,即主線程

可以將耗時的執行路徑(如:網路請求)放在其他線程中執行

建立線程的目的就是為了開啟一條新的執行路徑,運行指定的代碼,與主線程中的代碼實現同時運行。

 

棧區:主線程棧區的1M,非常非常寶貴。一個進程,至少有一個線程(主線程),不能殺掉一個線程!但是可以暫停、休眠。

2、多任務系統調度

 

說明:每個應用程式由作業系統分配的短暫的時間片(Timeslice)輪流使用CPU,由於CPU對每個時間片的處理速度非常快,因此,使用者看來好像這些任務在同時執行的。

並發:指兩個或多個任務在同一時間間隔內發生,但是,在任意一個時刻點上,CPU只會處理一個任務。

3、優勢、弊端以及誤區

優勢:

(1) 充分發揮多核處理器優勢,將不同線程任務分配給不同的處理器,真正進入“並行運算”狀態

(2) 將耗時的任務分配到其他線程執行,由主線程負責統一更新介面會使應用程式更加流暢,使用者體驗更好

(3) 當硬體處理器的數量增加,程式會運行更快,而程式無需做任何調整

弊端:

建立線程會消耗記憶體空間和CPU時間,線程太多會降低系統的運行效能

誤區:

多線程技術是為了並發執行多項任務,不會提高單個演算法本身的執行效率

4iOS的三種多線程技術

NSThread

(1) 使用NSThread對象建立一個線程非常方便

(2) 但是!要使用NSThread管理多個線程非常困難,不推薦使用

(3) 技巧!使用[NSThread currentThread]獲得任務所線上程,適用於這三種技術

(4) 使線程休眠0.3秒:[NSThread sleepForTimeInterval:0.3f];

NSOperation/NSOperationQueue

(1)是使用GCD實現的一套Objective-C的API

(2)是物件導向的線程技術

(3)提供了一些在GCD中不容易實現的特性,如:限制最大並發數量、操作之間的依賴關係

GCD —— Grand Central Dispatch

(1)是基於C語言的底層API

(2)用Block定義任務,使用起來非常靈活便捷

(3)提供了更多的控制能力以及操作隊列中所不能使用的底層函數

提示:iOS的開發人員,需要瞭解三種多線程技術的基本使用,因為在實際開發中會根據實際情況選擇不同的多線程技術。

4GCD基本思想

GCD的基本思想是就將操作s放在隊列s中去執行。

(1) 操作使用Blocks定義

(2) 隊列負責調度任務執行所在的線程以及具體的執行時間

(3) 隊列的特點是先進先出(FIFO)的,新添加至對列的操作都會排在隊尾

提示:GCD的函數都是以dispatch(指派、調度)開頭的

隊列:

dispatch_queue_t

串列隊列,隊列中的任務會順序執行

並行隊列,隊列中的任務通常會並發執行

操作:

(1)dispatch_async 非同步作業,會並發執行,無法確定任務的執行順序

(2)dispatch_sync 同步操作,會依次順序執行,能夠決定任務的執行順序

5、串列隊列

 

例如:

- (void)viewDidLoad

{

    [super viewDidLoad];

    NSLog(@"%@", [NSThread currentThread]);

    [self gcdDemo1];

   

}

- (void)gcdDemo1

{

    // 將操作放在隊列中

    // 在C語言函數中,定義類型,絕大多數的結尾是_t或者ref

    // 使用串列隊列的非同步任務非常非常非常有用!建立子線程是有開銷的,不能無休止建立線程

    // 即可以保證效率(建立一個子線程),用能夠實現並發

    // 應用案例:

    // 1> 從網路上上下載圖片

    // 2> 濾鏡(高光,紅眼...)

   

    dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);

// [NSThread currentThread]獲得當前線程

    for (int i = 0; i < 10; ++i) {

        // 非同步任務順序執行,但是如果用在串列隊列中,仍然會依次順序執行

        dispatch_async(q, ^{

            NSLog(@"%@%d ", [NSThread currentThread],i);

        });

}

輸出列印結果:

每次運行結果都是一樣的:

如果將上述代碼中非同步任務順序執行部分代碼改為如下同步任務順序執行:

for (int i = 0; i < 10; ++i) {

        // 同步任務順序執行

        dispatch_sync(q, ^{

            NSLog(@"%@ %d", [NSThread currentThread], i);

        });

    }

則輸出列印結果為:

上述同步任務順序執行在實際開發中幾乎用不到,但面試可能會問到。

6並行隊列

 

例如:

- (void)viewDidLoad

{

    [super viewDidLoad];

    NSLog(@"%@", [NSThread currentThread]);

    [self gcdDemo2];

   

}

 

- (void)gcdDemo2

{

    // 特點:沒有隊形,執行順序程式員不能控制!

    // 應用情境:並發執行任務,沒有先後循序關聯性

    // 並行隊列容易出錯!並行隊列不能控制建立線程的數量!

    dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcd2", DISPATCH_QUEUE_CONCURRENT);

   

    for (int i = 0; i < 10; ++i) {

        // 非同步任務順序執行

        dispatch_async(q, ^{

            NSLog(@"%@ %d", [NSThread currentThread], i);

        });

    }

}

輸出列印結果:

每次運行結果num的值和最後面的數字都不一樣:

如果將上述代碼中非同步任務順序執行部分代碼改為如下同步任務順序執行:

for (int i = 0; i < 10; ++i) {

        // 同步任務順序執行

        dispatch_sync(q, ^{

            NSLog(@"%@ %d", [NSThread currentThread], i);

        });

}

則運行輸出列印結果為:

7、全域隊列

 

例如(與並行隊列效果一樣):

#pragma mark - 全域隊列(蘋果為了方便多線程的設計,提供一個全域隊列,供所有的APP共同使用)

- (void)gcdDemo3

{

    // 全域隊列與並行隊列的區別

    // 1> 不需要建立,直接GET就能用

    // 2> 兩個隊列的執行效果相同

    // 3> 全域隊列沒有名稱,調試時,無法確認準確隊列

   

    // 記住:在開發中永遠用DISPATCH_QUEUE_PRIORITY_DEFAULT

    // 多線程的優先順序反轉!低優先順序的線程阻塞了高優先順序的線程!

dispatch_queue_t q =

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

   

    for (int i = 0; i < 10; ++i) {

        // 同步任務順序執行

        dispatch_sync(q, ^{

            NSLog(@"%@ %d", [NSThread currentThread], i);

        });

    }

   

    for (int i = 0; i < 10; ++i) {

        // 非同步任務,並發執行,但是如果在穿行隊列中,仍然會依次順序執行

        dispatch_async(q, ^{

            // [NSThread currentThread] 可以在開發中,跟蹤當前線程

            // num = 1,表示主線程

            // num = 2,表示第2個子線程。。。

            NSLog(@"%@ %d", [NSThread currentThread], i);

        });

    }

}

運行列印結果:

8主隊列(主線程隊列)

 

例如:

- (void)gcdDemo4

{

    // 每一個應用程式都只有一個主線程

    // 為什麼需要在主線程上工作呢?

    // iOS開發中,所有UI的更新工作,都必須在主線程上執行!

    dispatch_queue_t q = dispatch_get_main_queue();

   

    // 主線程是有工作的,而且除非將程式殺掉,否則主線程的工作永遠不會結束!

    //開啟同步任務會導致主線程阻塞

    //dispatch_sync(q, ^{

    //    NSLog(@"come here baby!");

   // });

   

    // 非同步任務,在主線程上運行,同時是保持隊形的

    for (int i = 0; i < 10; ++i) {

        dispatch_async(q, ^{

            NSLog(@"%@ - %d", [NSThread currentThread], i);

        });

    }

}

運行輸出列印結果:

9、不同隊列中嵌套dispatch_sync的結果

// 全域隊列,都在主線程上執行,不會死結

dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 並行隊列,都在主線程上執行,不會死結

dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_CONCURRENT);

// 串列隊列,會死結,但是會執行嵌套同步操作之前的代碼

dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);

// 直接死結

dispatch_queue_t q = dispatch_get_main_queue();

dispatch_sync(q, ^{

    NSLog(@"同步任務 %@", [NSThread currentThread]);

    dispatch_sync(q, ^{

        NSLog(@"同步任務 %@", [NSThread currentThread]);

    });

});

10dispatch_sync的應用情境

阻塞並行隊列的執行,要求某一操作執行後再進行後續操作,如使用者登入,確保塊代碼之外的局部變數確實被修改。

11、編程選擇

串列隊列,同步任務:不需要建立線程

串列隊列,非同步任務:需要一個子線程,線程的建立和回收不需要程式員參與!是最安全的一個選擇。

並行隊列,同步任務:不需要建立線程

並行隊列,非同步任務:有多少個任務,就開N個線程執行,

無論什麼隊列和什麼任務,線程的建立和回收不需要程式員參與。

線程的建立回收工作是由隊列負責的

“並發”編程,為了讓程式員從負責的線程式控制制中解脫出來!只需要面對隊列和任務

12GCD總結

GCD

(1) 通過GCD,開發人員不用再直接跟線程打交道,只需要向隊列中添加代碼塊即可

(2) GCD在後端管理著一個線程池,GCD不僅決定著代碼塊將在哪個線程被執行,它還根據可用的系統資源對這些線程進行管理。從而讓開發人員從線程管理的工作中解放出來,通過集中的管理線程,緩解大量線程被建立的問題

(3) 使用GCD,開發人員可以將工作考慮為一個隊列,而不是一堆線程,這種並行的抽象模型更容易掌握和使用

(4) 串列中,同步中嵌套同步會導致阻塞

GCD的隊列

(1)GCD公開有5個不同的隊列:運行在主線程中的主隊列,3 個不同優先順序的後台隊列,以及一個優先順序更低的後台隊列(用於 I/O)

(2)自訂隊列:串列和並行隊列。自訂隊列非常強大,建議在開發中使用。在自訂隊列中被調度的所有Block最終都將被放入到系統的全域隊列中和線程池中

(3)在執行任務的時候,首先執行隊列中第一個加入的任務,再執行第二個、第三個….依次執行

(4)提示:不建議使用不同優先順序的隊列,因為如果設計不當,可能會出現優先順序反轉,即低優先順序的操作阻塞高優先順序的操作

綜上:

GCD的任務

 1> disptach_sync  沒有建立線程的慾望,就在當前線程執行

    最主要的目的,阻塞並行隊列任務的執行,只有當前的同步任務執行完畢後,後續的任務才能夠執行

    應用情境:使用者登入!

 2> dispatch_async 有建立線程的慾望,但是建立多少條線程,取決與隊列的類型

 

 GCD的隊列

 1> 串列隊列  類似於跑步,只有一條跑道,最多能夠有兩條

    如果存在非同步任務,就會在新線程中執行非同步任務,而同步任務依舊在當前線程中執行

 2> 並行隊列  類似與賽跑,具體跑道的數量,由系統決定

GCD隊列:

 

iOS開發之多線程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.