iOS中多線程知識總結:進程、線程、GCD、串行隊列、並行隊列、全局隊列、主線程隊列、同步任務、異步任務等

iOS中多線程知識總結:進程、線程、GCD、串行隊列、並行隊列、全局隊列、主線程隊列、同步任務、異步任務等(有示例代碼)


進程

正在運行中的程序被稱作進程,負責程序運行的內存分配;每一個進程都有自己獨立的虛擬內存空間。


線程

進程中的一個對立的執行路徑被稱爲線程,一個進程中至少包含一條線程,該線程被稱爲主線程。

多線程

多創建一條或者多條線程的,目的就是爲了開啓一條新的執行路徑,運行指定的代碼,與主線程中的代碼實現同時運行。

優勢

  • 充分發揮多核處理器優勢,將不同線程任務分配給不同的處理器,真正進入“並行運算”狀態。
  • 將耗時的任務分配到其他線程執行,由主線程負責統一更新界面會使應用程序更加流暢,用戶體驗更好。
  • 當硬件處理器的數量增加,程序會運行更快,而程序無需做任何調整。

弊端

  • 新建線程會消耗內存空間和CPU時間,線程太多會降低系統的運行性能。

誤區

  • 多線程技術是爲了併發執行多項任務,不會提高單個算法本身的執行效率。

iOS中的三種多線程技術

NSThread

  • 使用NSThread對象建立一個線程非常方便。
  • 但是!要使用NSThread管理多個線程非常困難,不推薦使用。
  • 技巧!使用[NSThread currentThread]跟蹤任務所在線程,適用於這三種技術。

NSOperation/NSOperationQueue

  • 是使用GCD實現的一套Objective-C的API。
  • 是面向對象的線程技術。
  • 提供了一些在GCD中不容易實現的特性,如:限制最大併發數量、操作之間的依賴關係。
  • 蘋果官方現在建議大家使用該多線程技術,但現在仍然很多人使用GCD技術,因爲GCD使用較爲方便。

GCD —— Grand Central Dispatch

  • Grand Central Dispatch (GCD)是Apple開發的一個多核編程的解決方法,稱作大中心調度。該方法在Mac OS X 10.6雪豹中首次推出,並隨後被引入到了iOS4.0中。GCD是一個替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術的很高效和強大的技術。
  • 是基於C語言的底層API。
  • 用Block定義任務,使用起來非常靈活便捷。
  • 提供了更多的控制能力以及操作隊列中所不能使用的底層函數。

隊列

隊列是先進先出(FIFO)結構的,其主要的任務主要是負責線程的創建、回收工作,不論什麼隊列和什麼任務都不需要程序員參與,減輕了程序員的工作。

GCD的隊列

  • 運行在主線程中的主隊列。
  • 3 個不同優先級的後臺隊列。
  • 一個優先級更低的後臺隊列(用於 I/O)。

自定義隊列

  • 串行隊列
  • 並行隊列。
  • 自定義隊列非常強大,建議在開發中使用。在自定義隊列中被調度的所有Block最終都將被放入到系統的全局隊列中和線程池中。
    GCD隊列示意圖
    從圖中可以看出串行隊列、並行隊列都屬於默認優先級的GCD隊列。
    提示:不建議使用不同優先級的隊列,因爲如果設計不當,可能會出現優先級反轉,即低優先級的操作阻塞高優先級的操作。

串行隊列

隊列中的任務只會順序執行(類似跑步),創建如下:

dispatch_queue_t q = dispatch_queue_create(“threadName”, DISPATCH_QUEUE_SERIAL);

“threadName”是隊列名稱,用於在調試時輔助。

並行隊列

隊列中的任務通常會併發執行(類似賽跑),創建如下:

dispatch_queue_t q = dispatch_queue_create("threadName", DISPATCH_QUEUE_CONCURRENT);

“threadName”是隊列名稱,用於在調試時輔助。

全局隊列

是系統的,蘋果爲了方便多線程的設計,提供一個全局隊列,供所有的APP共同使用,直接拿過來(GET)用就可以;與並行隊列類似,但調試時,無法確認操作所在隊列,獲得方法如下:

dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

主線程隊列

每一個應用程序對應唯一一個主隊列,直接GET即可;在多線程開發中,使用主隊列更新UI,獲得方法如下:

dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

任務

同步任務

必須按照順序執行的任務,利用如下代碼添加一個同步任務:

dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)

異步任務

執行順序不確定,那個任務線搶佔到CPU資源誰先執行,會併發執行,利用如下代碼添加一個異步任務:

dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)

不同隊列中添加不同任務運行結果的總結

串行隊列+同步任務

不會創建新的線程,所有任務會在同一線程中按順序執行,運行如下代碼:

- (void)gcdDemo1 {
  // 1.創建隊列
  dispatch_queue_t q =
      dispatch_queue_create("kwjThread1", DISPATCH_QUEUE_SERIAL);
  // 2.向隊列中添加任務
  for (int i = 0; i < 10; i++) {
    dispatch_sync(q, ^{
      NSLog(@"%@ %d", [NSThread currentThread], i);
    });
  }
  }
}

運行結果:
運行結果

串行隊列+異步任務

操作需要一個子線程,會新建線程、線程的創建和回收不需要程序員參與,操作順序執行,是“最安全的選擇”,運行如下代碼:

- (void)gcdDemo1 {
  // 1.創建隊列
  dispatch_queue_t q =
      dispatch_queue_create("kwjThread1", DISPATCH_QUEUE_SERIAL);
  // 2.向隊列中添加任務
  for (int i = 0; i < 10; i++) {
    dispatch_async(q, ^{
      NSLog(@"%@ %d", [NSThread currentThread], i);
    });
  }
}

運行結果:
運行結果

並行隊列+同步任務

不會創建新的線程,所有任務會在同一線程中按順序執行,運行如下代碼:

- (void)gcdDemo2 {
  // 創建隊列
  dispatch_queue_t q =
      dispatch_queue_create("kwjThread2", DISPATCH_QUEUE_CONCURRENT);
  // 同步任務,不會開啓新的線程,按順序進行
  for (int i = 0; i < 10; i++) {
    dispatch_sync(q, ^{
      NSLog(@"%@ %d", [NSThread currentThread], i);
    });
  }
}

運行結果:
這裏寫圖片描述

並行隊列+異步任務

操作會新建多個線程(有多少任務,就開N個線程執行)、操作無序執行;隊列前如果有其他任務,會等待前面的任務完成之後再執行;場景:既不影響主線程,又不需要順序執行的操作!運行如下代碼:

- (void)gcdDemo2 {
  // 創建隊列
  dispatch_queue_t q =
      dispatch_queue_create("kwjThread2", DISPATCH_QUEUE_CONCURRENT);
  // 異步任務,有多少任務,就會開啓N個線程
    for (int i = 0; i < 10; i++) {
      dispatch_async(q, ^{
        NSLog(@"%@ %d", [NSThread currentThread], i);
      });
    }
}

運行結果:
運行結果

全局隊列+同步任務

不會創建新的線程,所有任務會在同一線程中按順序執行,運行如下代碼:

- (void)gcdDemo3{
    // 取得全局隊列
    // 記住:在開發中永遠用DISPATCH_QUEUE_PRIORITY_DEFAULT
    dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 添加任務
    // 同步任務
    NSLog(@"%@KWJ", [NSThread currentThread]);
    for (int i = 0; i < 10; i++) {
        dispatch_sync(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
}

運行結果:
運行結果

全局隊列+異步任務

操作會新建多個線程、操作無序執行,隊列前如果有其他任務,會等待前面的任務完成之後再執行,運行如下代碼:

 - (void)gcdDemo3{
    // 取得全局隊列
    dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 添加任務

    // 異步任務
    for (int i = 0; i < 10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
}
@end

運行結果:
這裏寫圖片描述

全局隊列與併發隊列比較

  • 不需要創建,直接GET就能用
  • 兩個隊列的執行效果相同
  • 全局隊列沒有名稱,調試時,無法確認準確隊列

主隊列+同步任務

主隊列中添加同步任務會發生阻塞(死鎖),運行如下代碼:

- (void)gcdDemo4{
    // 獲得主隊列
    dispatch_queue_t q = dispatch_get_main_queue();
    NSLog(@"%@,我是:",[NSThread currentThread]);
    // 添加同步任務
    dispatch_sync(q, ^{
        NSLog(@"%@,KWJ",[NSThread currentThread]);
    });
    NSLog(@"haha");
}

運行結果:
這裏寫圖片描述

在主隊列開啓同步任務,爲什麼會阻塞線程?

在主隊列開啓同步任務,因爲主隊列是串行隊列,裏面的線程是有順序的,先執行完一個線程才執行下一個線程,而主隊列始終就只有一個主線程,主線程是不會執行完畢的,因爲他是無限循環的,除非關閉應用程序。因此在主線程開啓一個同步任務,同步任務會想搶佔執行的資源,而主線程任務一直在執行某些操作,不肯放手。兩個的優先級都很高,最終導致死鎖,阻塞線程了。

主隊列+異步操作

異步任務在主線程上運行,同時是保持隊形的,操作都應該在主線程上順序執行的,不存在異步的概念,運行如下代碼:

- (void)gcdDemo4{
    // 獲得主隊列
    dispatch_queue_t q = dispatch_get_main_queue();
    NSLog(@"%@KWJ",[NSThread currentThread]);
    for (int i = 0; i < 10; ++i) {
        dispatch_async(q, ^{
            NSLog(@"%@ - %d", [NSThread currentThread], i);
        });
    }
}

運行結果:
運行結果

在主隊列開啓異步任務,不會開啓新的線程而是依然在主線程中執行代碼塊中的代碼。爲什麼不會阻塞線程?

主隊列開啓異步任務,雖然不會開啓新的線程,但是他會把異步任務降低優先級,等閒着的時候,就會在主線程上執行異步任務。


不同隊列中嵌套dispatch_sync的結果

嵌套代碼

dispatch_sync(q, ^{
    NSLog(@"同步任務 %@", [NSThread currentThread]);
    dispatch_sync(q, ^{
        NSLog(@"同步任務 %@", [NSThread currentThread]);
    });
});

在串行隊列中

串行隊列,嵌套上述代碼會死鎖,但是會執行嵌套同步操作之前的代碼。

在並行隊列中

並行隊列,嵌套上述代碼,不會死鎖,都在主線程上執行。

在全局隊列中

全局隊列,嵌套上述代碼,不會死鎖,都在主線程上執行。

在主隊列中

主隊列,嵌套上述代碼直接死鎖。


GCD小結

  • 通過GCD,開發者不用再直接跟線程打交道,只需要向隊列中添加代碼塊即可。
  • GCD在後端管理着一個線程池,GCD不僅決定着代碼塊將在哪個線程被執行,它還根據可用的系統資源對這些線程進行管理。從而讓開發者從線程管理的工作中解放出來,通過集中的管理線程,緩解大量線程被創建的問題。
  • 使用GCD,開發者可以將工作考慮爲一個隊列,而不是一堆線程,這種並行的抽象模型更容易掌握和使用。

以上即爲本人最近在學習了iOS開發中多線程技術後的簡單總結,其實大部分都是前人的總結,本人大部分工作都是整理,並加入一些個人的理解,還請大家有錯誤在下面留言指出。
大家也可以加我QQ:947124563進行交流學習。

發佈了25 篇原創文章 · 獲贊 23 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章