你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS(CGD)

iOS(CGD)

編輯:IOS開發綜合

概念

隊列 (dispatch_queue_t)

隊列名稱在調試時輔助,無論什麼隊列和任務,線程的創建和回收不需要程序員操作,有隊列負責。

串行隊列:

隊列中的任務只會順序執行

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

並行隊列:

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

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

全局隊列:

是系統的,直接拿過來(GET)用就可以;與並行隊列類似,但調試時,無法確認操作所在隊列

dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

主隊列:

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

dispatch_queue_t q = dispatch_get_main_queue();

操 作:

dispatch_async異步操作,會並發執行,無法確定任務的執行順序;

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

備 注:

全局隊列可認為是並行隊列的一個特例,這裡不再列舉。

 

線程、任務和隊列對比

\

異步、同步 & 並行、串行的特點

\

一條重要的准則

一般來說,我們使用GCD的最大目的是在新的線程同時執行多個任務,這意味著我們需要兩項條件:

能開啟新的線程任務可以同時執行結合以上兩個條件,也就等價“開啟新線程的能力 + 任務同步執行的權利”,只有在滿足能力與權利這兩個條件的前提下,我們才可以在同時執行多個任務。

所有組合的特點

\  

(一)異步執行 + 並行隊列

實現代碼:
 
//異步執行 + 並行隊列
- (void)asyncConcurrent{
    //創建一個並行隊列
    dispatch_queue_t queue = dispatch_queue_create("標識符", DISPATCH_QUEUE_CONCURRENT);

    NSLog(@"---start---");

    //使用異步函數封裝三個任務
    dispatch_async(queue, ^{
        NSLog(@"任務1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務3---%@", [NSThread currentThread]);
    });

    NSLog(@"---end---");
}
打印結果:
---start---
  ---end---
  任務3---{number = 5, name = (null)}
  任務2---{number = 4, name = (null)}
  任務1---{number = 3, name = (null)}
解釋
異步執行意味著 可以開啟新的線程任務可以先繞過不執行,回頭再來執行 並行隊列意味著 任務之間不需要排隊,且具有同時被執行的“權利” 兩者組合後的結果 開了三個新線程函數在執行時,先打印了start和end,再回頭執行這三個任務這三個任務是同時執行的,沒有先後,所以打印結果是“任務3-->任務2-->任務1”
步驟圖
\  

(二)異步執行 + 串行隊列

實現代碼:
 
//異步執行 + 串行隊列
- (void)asyncSerial{
    //創建一個串行隊列
    dispatch_queue_t queue = dispatch_queue_create("標識符", DISPATCH_QUEUE_SERIAL);

    NSLog(@"---start---");
    //使用異步函數封裝三個任務
    dispatch_async(queue, ^{
        NSLog(@"任務1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}

打印結果:
---start---
 ---end---
任務1---{number = 3, name = (null)}
任務2---{number = 3, name = (null)}
任務3---{number = 3, name = (null)}
 
解釋
異步執行意味著 可以開啟新的線程任務可以先繞過不執行,回頭再來執行 串行隊列意味著 任務必須按添加進隊列的順序挨個執行 兩者組合後的結果 開了一個新的子線程函數在執行時,先打印了start和end,再回頭執行這三個任務這三個任務是按順序執行的,所以打印結果是“任務1-->任務2-->任務3”
 
步驟圖
\
 

(三)同步執行 + 並行隊列

實現代碼:
//同步執行 + 並行隊列
- (void)syncConcurrent{
    //創建一個並行隊列
    dispatch_queue_t queue = dispatch_queue_create("標識符", DISPATCH_QUEUE_CONCURRENT);

    NSLog(@"---start---");
    //使用同步函數封裝三個任務
    dispatch_sync(queue, ^{
        NSLog(@"任務1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}

打印結果:
---start---
  任務1---{number = 1, name = main}
  任務2---{number = 1, name = main}
  任務3---{number = 1, name = main}
  ---end---

解釋
同步執行執行意味著 不能開啟新的線程任務創建後必須執行完才能往下走 並行隊列意味著 任務必須按添加進隊列的順序挨個執行 兩者組合後的結果 所有任務都只能在主線程中執行函數在執行時,必須按照代碼的書寫順序一行一行地執行完才能繼續 注意事項 在這裡即便是並行隊列,任務可以同時執行,但是由於只存在一個主線程,所以沒法把任務分發到不同的線程去同步處理,其結果就是只能在主線程裡按順序挨個挨個執行了
 
步驟圖
\

(四)同步執行+ 串行隊列

實現代碼:
- (void)syncSerial{
    //創建一個串行隊列
    dispatch_queue_t queue = dispatch_queue_create("標識符", DISPATCH_QUEUE_SERIAL);

    NSLog(@"---start---");
    //使用異步函數封裝三個任務
    dispatch_sync(queue, ^{
        NSLog(@"任務1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}

打印結果:
  ---start---
  任務1---{number = 1, name = main}
  任務2---{number = 1, name = main}
  任務3---{number = 1, name = main}
  ---end---

解釋
這裡的執行原理和步驟圖跟“同步執行+並發隊列”是一樣的,只要是同步執行就沒法開啟新的線程,所以多個任務之間也一樣只能按順序來執行
 

(五)異步執行+主隊列

實現代碼:
- (void)asyncMain{
    //獲取主隊列
    dispatch_queue_t queue = dispatch_get_main_queue();

    NSLog(@"---start---");
    //使用異步函數封裝三個任務
    dispatch_async(queue, ^{
        NSLog(@"任務1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}

打印結果:
  ---start---
  ---end---
  任務1---{number = 1, name = main}
  任務2---{number = 1, name = main}
  任務3---{number = 1, name = main}

解釋
異步執行意味著
可以開啟新的線程
任務可以先繞過不執行,回頭再來執行
主隊列跟串行隊列的區別
隊列中的任務一樣要按順序執行
主隊列中的任務必須在主線程中執行,不允許在子線程中執行
以上條件組合後得出結果:
所有任務都可以先跳過,之後再來“按順序”執行
步驟圖
\
 
 

(六)同步執行+主隊列(死鎖)

實現代碼:
- (void)syncMain{
    //獲取主隊列
    dispatch_queue_t queue = dispatch_get_main_queue();

    NSLog(@"---start---");
    //使用同步函數封裝三個任務
    dispatch_sync(queue, ^{
        NSLog(@"任務1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任務3---%@", [NSThread currentThread]);
    });
    NSLog(@"---end---");
}

打印結果:
 ---start---

解釋
  • 主隊列中的任務必須按順序挨個執行
  • 任務1要等主線程有空的時候(即主隊列中的所有任務執行完)才能執行
  • 主線程要執行完“打印end”的任務後才有空
  • “任務1”和“打印end”兩個任務互相等待,造成死鎖
步驟圖

\

(七)知識拓展

1. dispatch_sync同步應用場景
-(void)loginAction
{
    //阻塞並行隊列的執行,要求某一操作執行後再進行後續操作,如用戶登錄
    //確保塊代碼之外的局部變量確實被修改
    dispatch_queue_t q = dispatch_queue_create("cn.login", DISPATCH_QUEUE_CONCURRENT);
    __block BOOL logon = NO;
    dispatch_sync(q, ^{
        NSLog(@"模擬耗時操作 %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:2.0f];
        NSLog(@"模擬耗時完成 %@", [NSThread currentThread]);
        logon = YES;
    });
    
    dispatch_async(q, ^{
        
        NSLog(@"登錄完成的處理 %@", [NSThread currentThread]);
    });
}

2. ios三種多線程技術:

  1.NSThread

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

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

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

  2.NSOperation/NSOperationQueue

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

    (2)是面向對象的線程技術

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

  3.GCD —— Grand Central Dispatch

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

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

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

 

3. 隊列和線程的區別:

隊列:是管理線程的,相當於線程池,能管理線程什麼時候執行。

串行隊列:隊列中的線程按順序執行(不會同時執行)

並行隊列:隊列中的線程會並發執行,可能會有一個疑問,隊列不是先進先出嗎,如果後面的任務執行完了,怎麼出去的了。這裡需要強調下,任務執行完畢了,不一定出隊列。只有前面的任務執行完了,才會出隊列。

4. 主線程隊列和GCD創建的隊列也是有區別的。

主線程隊列和GCD創建的隊列是不同的。在GCD中創建的隊列優先級沒有主隊列高,所以在GCD中的串行隊列開啟同步任務裡面沒有嵌套任務是不會阻塞主線程,只有一種可能導致死鎖,就是串行隊列裡,嵌套開啟任務,有可能會導致死鎖。

主線程隊列中不能開啟同步,會阻塞主線程。只能開啟異步任務,開啟異步任務也不會開啟新的線程,只是降低異步任務的優先級,讓cpu空閒的時候才去調用。而同步任務,會搶占主線程的資源,會造成死鎖。

5.線程:裡面有非常多的任務(同步,異步)

同步與異步的區別:

同步任務優先級高,在線程中有執行順序,不會開啟新的線程。

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

6. 主線程隊列注意:

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

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

7.在主隊列開啟同步任務,為什麼會阻塞線程?

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

8. 串行隊列開啟異步任務後嵌套同步任務造成死鎖

 

- (void)serial_queue_deadlock

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

    dispatch_async(q, ^{
 
        NSLog(@"異步任務 %@", [NSThread currentThread]);

        // 下面開啟同步造成死鎖:因為串行隊列中線程是有執行順序的,需要等上面開啟的異步任務執行完畢,才會執行下面開啟的同步任務。而上面的異步任務還沒執行完,要到下面的大括號才算執行完畢,而下面的同步任務已經在搶占資源了,就會發生死鎖。

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

}

9.串行隊列開啟同步任務後嵌套同步任務造成死鎖

 

- (void)serial_queue_deadlock
{
    dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(q, ^{
        NSLog(@"同步任務 %@", [NSThread currentThread]);
        // 下面開啟同步造成死鎖:因為串行隊列中線程是有執行順序的,需要等上面開啟的同步任務執行完畢,才會執行下面開啟的同步任務。而上面的同步任務還沒執行完,要到下面的大括號才算執行完畢,而下面的同步任務已經在搶占資源了,就會發生死鎖。
        dispatch_sync(q, ^{
            NSLog(@"同步任務 %@", [NSThread currentThread]);
        });
 
    });

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


  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved