1. 程式人生 > >iOS 多執行緒: 正確認識 GCD 佇列型別

iOS 多執行緒: 正確認識 GCD 佇列型別

在面試或者跟一些有 ios 程式設計經驗的人聊到關於 GCD 的佇列型別的問題.

很多人說自定義的 queue 是序列佇列.

這種說法在一定程度上是不對的, 下面具體再說.

今天跟大家聊聊 GCD 中的佇列型別問題.

------------------------------------------------------------------------------------------------

目前, GCD 有三種佇列型別.

* main queue:     主佇列. 

* global queue:   全域性佇列.

* custom queue: 自定義佇列.

------------------------------------------------------------------------------------------------

下面具體聊聊吧!

1. main queue

* 獲取方式

dispatch_get_main_queue()

*  細說

一般使用 main queue, 都是在該執行緒中操作 UI 相關的.

也就是說, 在 main queue 中執行的任務會在主執行緒中執行.

主執行緒只有一個, main queue是與主執行緒相關的,所以main queue 是序列佇列.

2. global queue

* 獲取方式

dispatch_get_global_queue(long identifier, unsigned long flags);

第一個引數是執行緒的優先順序.

第二個引數是保留引數.一般會設定為 0.

可以參考官方註釋

/*!
 * @function dispatch_get_global_queue
 *
 * @abstract
 * Returns a well-known global concurrent queue of a given quality of service
 * class.
 *
 * @discussion
 * The well-known global concurrent queues may not be modified. Calls to
 * dispatch_suspend(), dispatch_resume(), dispatch_set_context(), etc., will
 * have no effect when used with queues returned by this function.
 *
 * @param identifier
 * A quality of service class defined in qos_class_t or a priority defined in
 * dispatch_queue_priority_t.
 *
 * It is recommended to use quality of service class values to identify the
 * well-known global concurrent queues:
 *  - QOS_CLASS_USER_INTERACTIVE
 *  - QOS_CLASS_USER_INITIATED
 *  - QOS_CLASS_DEFAULT
 *  - QOS_CLASS_UTILITY
 *  - QOS_CLASS_BACKGROUND
 *
 * The global concurrent queues may still be identified by their priority,
 * which map to the following QOS classes:
 *  - DISPATCH_QUEUE_PRIORITY_HIGH:         QOS_CLASS_USER_INITIATED
 *  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT
 *  - DISPATCH_QUEUE_PRIORITY_LOW:          QOS_CLASS_UTILITY
 *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:   QOS_CLASS_BACKGROUND
 *
 * @param flags
 * Reserved for future use. Passing any value other than zero may result in
 * a NULL return value.
 *
 * @result
 * Returns the requested global queue or NULL if the requested global queue
 * does not exist.
 */

* 細說

global queue 是併發佇列.可以設定其優先順序.


3. Custom queue

* 獲取方式

dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

* 細說

這些佇列是可以是序列的, 也可以是並行的。預設是序列的.
序列佇列可以保證任務是序列的, 保證了執行順序.類似鎖機制.

* 例子

(1). 預設是序列佇列.

    // 自定義佇列(NULL, 預設是序列佇列)
    dispatch_queue_t queue = dispatch_queue_create("gcd.mark", NULL);
    
    NSLog(@"create custom queue completed.");
    
    dispatch_async(queue, ^{
        // 模擬耗時
        [NSThread sleepForTimeInterval:2];
        NSLog(@"Run First Task");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"Run Sencond Task");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"Run Third Task");
    });

執行結果
// 執行結果
2015-10-31 23:33:14.267 dsds[87226:1308349] create custom queue completed.
2015-10-31 23:33:16.269 dsds[87226:1308582] Run First Task
2015-10-31 23:33:16.270 dsds[87226:1308582] Run Sencond Task
2015-10-31 23:33:16.270 dsds[87226:1308582] Run Third Task

也可以看出, 使用上述方式建立的 queue, 是序列佇列. 所以在開頭說別人說自定義 queue 是序列的, 並不一定錯.

接著看第二個例子.

(2).  指定為序列

// 指定為序列佇列
    dispatch_queue_t queue = dispatch_queue_create("gcd.mark", DISPATCH_QUEUE_SERIAL);
    
    NSLog(@"create custom queue completed.");
    
    dispatch_async(queue, ^{
        // 模擬耗時
        [NSThread sleepForTimeInterval:2];
        NSLog(@"Run First Task");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"Run Sencond Task");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"Run Third Task");
    });

執行結果跟例子(1)是一致的.

(3). 指定為並行

    // 指定為並行佇列
    dispatch_queue_t queue = dispatch_queue_create("gcd.mark", DISPATCH_QUEUE_CONCURRENT);
    
    NSLog(@"create custom queue completed.");
    
    dispatch_async(queue, ^{
        // 模擬耗時
        [NSThread sleepForTimeInterval:2];
        NSLog(@"Run First Task");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"Run Sencond Task");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"Run Third Task");
    });

執行結果
2015-10-31 23:37:06.052 dsds[87270:1310892] create custom queue completed.
2015-10-31 23:37:06.052 dsds[87270:1310988] Run Sencond Task
2015-10-31 23:37:06.052 dsds[87270:1311060] Run Third Task
2015-10-31 23:37:08.057 dsds[87270:1311055] Run First Task

可以看出, 不是按照順序執行的.