iOS 多線程與GCD

進程:系統中正在運行的一個程序,進程之間是相互獨立的,每個進程都有屬於自己的內存空間。比如手機中的 微信 應用和 印象筆記 應用,他們都是iOS系統中獨立的進程,有着自己的內存空間。

線程:進程內部的任務執行路徑,可簡單理解爲 一個程序它是按順序從上往下執行的, 這個執行順序我們可以把它看成是一條線,把這條線就叫做線程。進程若想執行任務,則必須得在線程下執行。也就是說進程至少有一個線程才能執行任務。

多線程的實現原理:雖然在同一時刻,CPU只能處理1條線程,但是CPU可以快速地在多條線程之間調度(切換),達到多線程併發的近似效果。

 

多線程的優點:

  1. 能適當提高程序的執行效率
  2. 能適當提高資源利用率(CPU、內存利用率)。

多線程的缺點:

  1. 創建線程是需要成本的:在棧空間的子線程512KB、主線程1MB,創建線程大約需要90毫秒的創建時間。
  2. 線程越多,CPU在調度線程上的開銷就越大。
  1. 線程越多,程序設計就越複雜:因爲要考慮到線程之間的通信,多線程的數據共享。

 

iOS主線程:刷新UI,響應UI事件

iOS子線程:異步執行,不影響主線程,處理耗時任務,如網絡請求,加載圖片,複雜運算

多線程安全:當多個線程訪問同一塊資源時,很容易引發數據錯亂和數據安全問題。就好比好幾個人在同時修改同一個表格,造成數據的錯亂。

 

多線程資源搶奪的解決方案

要給數據添加互斥鎖 。也就是說,當某線程訪問一個數據之前就要給數據加鎖,讓其不被其他的線程所修改。就好比一個人修改表格的時候給表格設置了密碼,那麼其他人就無法訪問文件了。當他修改文件之後,再講密碼撤銷,第二個人就可以訪問該文件了。

這裏的線程都爲子線程,如果給數據加了鎖,就等於將這些異步的子線程變成同步的了,這也叫做線程同步技術。

  • atomic:原子屬性,爲setter方法加鎖(默認就是atomic)
  • nonatomic:非原子屬性,不會爲setter方法加鎖

多線程在iOS中的應用:GCD

GCD的優勢:

  1. 自動利用更多的CPU內核(比如雙核、四核)
  2. 自動管理線程的生命週期(創建線程、調度任務、銷燬線程)
  3. 只需要告訴GCD想要執行什麼任務,不需要編寫任何線程管理代碼。

 GCD的使用步驟

  1. 開發者定製將要執行的任務
  2. 將任務添加到隊列中,GCD會自動將隊列中的任務取出,放到對應的線程中執行。

GCD的隊列可以分爲2大類型:

  1. 串行隊列:隊列中的任務按順序執行(不會同時執行)
  2. 並行隊列:隊列中的任務會併發執行,任務執行完畢,不一定出隊列。只有前面的任務執行完了,纔會出隊列。

GCD的任務2大類型:

  1. 同步任務:優先級高,在線程中有執行順序,不會開啓新的線程。
  2. 異步任務:優先級低,在線程中執行沒有順序,看cpu閒不閒。在主隊列中不會開啓新的線程,其他隊列會開啓新的線程

隊列:可理解爲是管理任務的,它裏面放着很多的任務,來管理這些任務的開啓順序,串行隊列開啓異步任務,是有順序

任務同步異步:決定的是任務的執行順序,並行隊列裏開啓同步任務是有執行順序的,只有異步纔沒有順序

串行隊列創建:

  1. 使用 dispatch_queue_create 函數創建串行隊列:創建串行隊列(隊列類型傳遞NULL或者DISPATCH_QUEUE_SERIAL)
  2. dispatch_queue_t queue = dispatch_queue_create("serial_queue", NULL);
  3. 使用主隊列(跟主線程相關聯的隊列)主隊列是GCD自帶的一種特殊的串行隊列:放在主隊列中的任務,都會放到主線程中執行。可以使用dispatch_get_main_queue()獲得系統提供的主隊列:

dispatch_queue_tqueue = dispatch_get_main_queue();

併發隊列的創建:

  1. 使用 dispatch_queue_create 函數創建併發隊列。

dispatch_queue_tqueue = dispatch_queue_create("concurrent.queue",DISPATCH_QUEUE_CONCURRENT);

  1. 使用 dispatch_get_global_queue 獲得全局併發隊列。GCD默認已經提供了全局的併發隊列,供整個應用使用,可以無需手動創建。

dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

多線程的應用

  1. 子線程與主線程的通信:有時需要在子線程處理一個耗時比較長的任務,並且此任務完成後,要在主線程執行另一個任務。

例如,從網絡加載圖片(在子線程),加載完成就更新UIView(在主線程)。

首先拿到全局併發隊列(或自己開啓一個子線程)來執行耗時的操作,然後在其完成block中拿到全局串行隊列來執行UI刷新的任務。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

//加載圖片

NSData*dataFromURL = [NSData dataWithContentsOfURL:imageURL];

UIImage*imageFromData = [UIImageimageWithData:dataFromURL];
dispatch_async(dispatch_get_main_queue(), ^{

//加載完成更新view

UIImageView*imageView = [[UIImageView alloc] initWithImage:imageFromData];         
      });     
  });

  1.  dispatch_once:用於在程序啓動到終止,只執行一次的代碼。此代碼被執行後,相當於自身全部被加上了註釋,不會再執行了。

爲了實現這個需求,我們需要使用 dispatch_once 讓代碼在運行一次後即刻被“雪藏”。

//使用dispatch_once函數能保證某段代碼在程序運行過程中只被執行1次

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    //只執行1次的代碼,這裏默認是線程安全的:不會有其他線程可以訪問到這裏
});

  1. dispatch_group:執行多個耗時的異步任務,但是隻能等到這些任務都執行完畢後,才能在主線程執行某個任務。爲了實現這個需求,我們需要讓將這些異步執行的操作放在 dispatch_group_async 函數中執行,最後再調用 dispatch_group_notify 來執行最後執行的任務。

dispatch_group_tgroup = dispatch_group_create();
  dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      // 執行1個耗時的異步操作
  });

dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      // 執行1個耗時的異步操作
  });

dispatch_group_notify(group,dispatch_get_main_queue(), ^{
      //等前面的異步操作都執行完畢後,回到主線程...
  });

  1. dispatch_barrier:有時要執行幾個不同的異步任務,但是我們還是要將其分成兩組:當第一組異步任務都執行完成後才執行第二組的異步任務。

爲了實現這個需求,我們需要使用dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);在兩組任務之間形成“柵欄”,使其“下方”的異步任務在其“上方”的異步任務都完成之前是無法執行的。

dispatch_queue_tqueue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue,^{
        NSLog(@"----任務1-----");
    });

dispatch_async(queue,^{
        NSLog(@"----任務2-----");
    });   

dispatch_barrier_async(queue, ^{
       NSLog(@"----任務柵欄-----");
    });

dispatch_async(queue,^{
        NSLog(@"----任務3-----");
    });

dispatch_async(queue,^{
        NSLog(@"----任務4-----");
    });

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