1. 程式人生 > >多執行緒:基礎內容

多執行緒:基礎內容

一、iOS中的常見多執行緒方案

  1. iOS 中 常見的多執行緒 方案
    在這裡插入圖片描述
  • pthread 和 NSThread 是 程式設計師自己建立 執行緒,自己管理什麼時候開啟,什麼時候結束。
  • GCD 和 NSOperation 則不用程式設計師自己管理,是系統管理。
  • NSThread 、 GCD 和 NSOperation 的底層使用的是 pthread。 他們都是包裝的 pthread。
  1. 面試題:iOS的多執行緒方案有哪幾種?你更傾向於哪一種?
  • iOS的多執行緒方案有哪幾種:pthread、NSThread、GCD 和 NSOperation
  • 你更傾向於哪一種: GCD 或 NSOperation

二、GCD 常用函式
在子個執行緒想要做某些事情,可以通過GCD 的 這幾個函式。

  1. GCD中有2個用來執行任務的函式
  • 用同步的方式執行任務

    • dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
    • queue:佇列
    • block:任務
  • 用非同步的方式執行任務

    • dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
  • GCD原始碼:https://github.com/apple/swift-corelibs-libdispatch

  1. 舉例:非同步方式執行任務
// 全域性併發佇列:姑且理解為系統為我們開啟的一些全域性執行緒
    /** dispatch_queue_t q = dispatch_get_global_queue(long identifier, unsigned long flags)
     引數型別為:
     long identifier:ios 8.0 告訴佇列執行任務的“服務質量 quality of service”,系統提供的引數有:
     
     QOS_CLASS_USER_INTERACTIVE 0x21,              使用者互動(希望儘快完成,使用者對結果很期望,不要放太耗時操作)
     QOS_CLASS_USER_INITIATED 0x19,                使用者期望(不要放太耗時操作)
     QOS_CLASS_DEFAULT 0x15,                        預設(不是給程式設計師使用的,用來重置對列使用的)
     QOS_CLASS_UTILITY 0x11,                        實用工具(耗時操作,可以使用這個選項)
     QOS_CLASS_BACKGROUND 0x09,                     後臺
     QOS_CLASS_UNSPECIFIED 0x00,                    未指定
     iOS 7.0 之前 優先順序
     DISPATCH_QUEUE_PRIORITY_HIGH 2                 高優先順序
     DISPATCH_QUEUE_PRIORITY_DEFAULT 0              預設優先順序
     DISPATCH_QUEUE_PRIORITY_LOW (-2)               低優先順序
     DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN  後臺優先順序
     
     BACKGROUND表示使用者不需要知道任務什麼時候完成,如果選擇這個選項速度慢得令人髮指,非常不利於除錯!對於優先順序推薦不要搞得太負責,就用最簡單,以免發生優先順序反轉。
     
     unsigned long flags:蘋果官方文件是這樣解釋的: Flags that are reserved for future use。標記是為了未來使用保留的!所以這個引數應該永遠指定為0
     如果做ios8.0與ios7.0的適配,可以這樣建立全域性佇列:
     dispatch_queue_t q = dispatch_get_global_queue(0, 0);
     試著用全域性佇列來做一下非同步操作,看看是否為併發執行,如下程式碼
     dispatch_queue_t q = dispatch_get_global_queue(0, 0);
     */
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    // 非同步方式執行任務
    // 列印結果是 3 ,也就是在 3號子執行緒執行的任務
    dispatch_async(queue, ^{  
        NSLog(@"執行任務 -%@",[NSThread currentThread]);
    });
	// 如果是同步方式執行任務
	// 列印結果是 1
	// 同步方式:在當前執行緒執行任務
   dispatch_sync(queue, ^{  
        NSLog(@"執行任務 -%@",[NSThread currentThread]);
   });

三、GCD的佇列

  1. GCD的佇列可以分為2大型別
  • 併發佇列(Concurrent Dispatch Queue)

    • 可以讓多個任務併發(同時)執行(自動開啟多個執行緒同時執行任務)
    • 併發功能只有在非同步(dispatch_async)函式下才有效
  • 序列佇列(Serial Dispatch Queue)

    • 讓任務一個接著一個地執行(一個任務執行完畢後,再執行下一個任務)
  1. 舉例: 併發佇列 + 非同步任務
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    // 非同步任務
    dispatch_async(queue, ^{
        for (int i = 0 ; i < 5; i++) {
            NSLog(@"執行任務1 - %@", [NSThread currentThread]);
        }
    });
    
    // 非同步任務
    dispatch_async(queue, ^{
        for (int i = 0 ; i < 5; i++) {
            NSLog(@"執行任務2 - %@", [NSThread currentThread]);
        }
    });

執行結果:
在這裡插入圖片描述

  1. 序列佇列 + 非同步任務
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    // 非同步任務
    dispatch_async(queue, ^{
        for (int i = 0 ; i < 5; i++) {
            NSLog(@"執行任務1 - %@", [NSThread currentThread]);
        }
    });
    
    // 非同步任務
    dispatch_async(queue, ^{
        for (int i = 0 ; i < 5; i++) {
            NSLog(@"執行任務2 - %@", [NSThread currentThread]);
        }
    });

結果:
在這裡插入圖片描述

  1. 序列佇列 + 同步任務: 只在主執行緒執行
    // 序列佇列
    dispatch_queue_t queue = dispatch_queue_create("WYGCD", DISPATCH_QUEUE_SERIAL);
    
    // 同步任務
    dispatch_sync(queue, ^{
        for (int i = 0 ; i < 3; i++) {
            NSLog(@"執行任務1 - %@", [NSThread currentThread]);
        }
    });
    
    // 同步任務
    dispatch_sync(queue, ^{
        for (int i = 0 ; i < 3; i++) {
            NSLog(@"執行任務2 - %@", [NSThread currentThread]);
        }
    });

結果:
在這裡插入圖片描述

  1. 不管是序列佇列還是併發佇列,只要跟 同步任務在一起,就是在當前執行緒按照順序執行。

四、容易混淆的術語

  1. 有4個術語比較容易混淆:同步、非同步、併發、序列
  2. 同步和非同步主要影響:能不能開啟新的執行緒
    • 同步:在當前執行緒中執行任務,不具備開啟新執行緒的能力
    • 非同步:在新的執行緒中執行任務,具備開啟新執行緒的能力
  3. 併發和序列主要影響:任務的執行方式
    • 併發:多個任務併發(同時)執行
    • 序列:一個任務執行完畢後,再執行下一個任務
  4. dispatch_sync 和 dispatch_async 用來控制是否要開啟新的執行緒
  5. 佇列的型別,決定了任務的執行方式(併發、序列)
    • 是一個接著一個執行
    • 還是 任務一起執行
  6. dispatch_async 只是具備了 開啟新執行緒的能力,不代表一定會開啟新執行緒。下面的程式碼就不具備開啟新執行緒,列印結果是 1 (主執行緒)。
    在這裡插入圖片描述
    • 這是因為 queue 是 主佇列
    • 也就是說 ,任務是放在了 主佇列,到時候就是在主執行緒中執行

五、各種佇列的執行效果
在這裡插入圖片描述

  • 主佇列 是一種特殊的序列佇列