iOS 多執行緒: 正確認識 GCD 佇列型別
阿新 • • 發佈:2019-02-05
在面試或者跟一些有 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
可以看出, 不是按照順序執行的.