GCD
Grand Central Dispatch
,是蘋果為多核的并行運算提出的解決方案,所以會自動合理地利用更多的CPU
內核(比如雙核、四核),最重要的是它會自動管理線程的生命周期(創建線程、調度任務、銷毀線程),完全不需要我們管理,我們只需要告訴干什么就行。同時它使用的也是 c語言
,不過由于使用了 Block
(Swift
里叫做閉包
),使得使用起來更加方便,而且靈活。所以基本上大家都使用GCD
這套方案。
任務和隊列
在GCD
中,加入了兩個非常重要的概念: 任務 和 隊列。
任務:即操作,你想要干什么,說白了就是一段代碼,在
GCD
中就是一個Block
,所以添加任務十分方便。任務有兩種執行方式:** 同步執行 **和 異步執行,他們之間的區別是是否會創建新的線程
。
同步(sync)
和異步(async)
的主要區別在于會不會阻塞當前線程,直到Block
中的任務執行完畢!
如果是同步(sync)
操作,它會阻塞當前線程并等待Block
中的任務執行完畢,然后當前線程才會繼續往下運行。
如果是異步(async)
操作,當前線程會直接往下執行,它不會阻塞當前線程。隊列:用于存放任務。一共有兩種隊列, 串行隊列 和 并行隊列。
串行隊列 中的任務會根據隊列的定義FIFO
的執行,一個接一個的先進先出的進行執行。
并行隊列 放到并行隊列的任務,GCD
也會FIFO
的取出來,但不同的是,它取出來一個就會放到別的線程,然后再取出來一個又放到另一個的線程。這樣由于取的動作很快,忽略不計,看起來,所有的任務都是一起執行的。不過需要注意,GCD
會根據系統資源控制并行的數量,所以如果任務很多,它并不會讓所有任務同時執行。
創建隊列
- 主隊列:這是一個特殊的 串行隊列。什么是主隊列,大家都知道吧,它用于刷新 UI,任何需要刷新 UI 的工作都要在主隊列執行,所以一般耗時的任務都要放到別的線程執行。
//OBJECTIVE-C
dispatch_queue_t queue = dispatch_get_main_queue();
//SWIFT
let queue = dispatch_get_main_queue()
-
自己創建的隊列:自己可以創建 串行隊列, 也可以創建 并行隊列。 看下面的代碼,它有兩個參數,其中第一個參數是
標識符
,用于DEBUG
的時候標識唯一的隊列,可以為空。大家可以看xcode的文檔查看參數意義,第二個才是最重要的。
第二個參數用來表示創建的隊列是串行
的還是并行
的,傳入DISPATCH_QUEUE_SERIAL
或NULL
表示創建串行隊列。傳入DISPATCH_QUEUE_CONCURRENT
表示創建并行隊列。
//OBJECTIVE-C
//串行隊列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue",
DISPATCH_QUEUE_SERIAL);
//并行隊列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
//SWIFT
//串行隊列
let queue = dispatch_queue_create("tk.bourne.testQueue", nil);
let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL)
//并行隊列
let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT)
- 全局并行隊列:只要是并行任務一般都加入到這個隊列。這是系統提供的一個并發隊列。
//OBJECTIVE-C
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//SWIFT
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
創建任務
-
同步任務:會阻塞當前線程 (SYNC)
OBJECTIVE-C
dispatch_sync(<#queue#>, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
});
SWIFT
dispatch_sync(<#queue#>, { () -> Void in
//code here
println(NSThread.currentThread())
})
-
異步任務:不會阻塞當前線程 (ASYNC)
OBJECTIVE-C
dispatch_async(<#queue#>, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
});
SWIFT
dispatch_async(<#queue#>, { () -> Void in
//code here
println(NSThread.currentThread())
})
隊列組
隊列組可以將很多隊列添加到一個組里,這樣做的好處是,當這個組里所有的任務都執行完了,隊列組會通過一個方法通知我們。下面是使用方法,這是一個很實用的功能。
OBJECTIVE-C
//1.創建隊列組
dispatch_group_t group = dispatch_group_create();
//2.創建隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//3.多次使用隊列組的方法執行任務, 只有異步方法
//3.1.執行3次循環
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 3; i++) {
NSLog(@"group-01 - %@", [NSThread currentThread]);
}
});
//3.2.主隊列執行8次循環
dispatch_group_async(group, dispatch_get_main_queue(), ^{
for (NSInteger i = 0; i < 8; i++) {
NSLog(@"group-02 - %@", [NSThread currentThread]);
}
});
//3.3.執行5次循環
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"group-03 - %@", [NSThread currentThread]);
}
});
//4.都完成后會自動通知
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"完成 - %@", [NSThread currentThread]);
});
SWIFT
//1.創建隊列組
let group = dispatch_group_create()
//2.創建隊列
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//3.多次使用隊列組的方法執行任務, 只有異步方法
//3.1.執行3次循環
dispatch_group_async(group, queue) { () -> Void in
for _ in 0..<3 {
NSLog("group-01 - %@", NSThread.currentThread())
}
}
//3.2.主隊列執行8次循環
dispatch_group_async(group, dispatch_get_main_queue()) { () -> Void in
for _ in 0..<8 {
NSLog("group-02 - %@", NSThread.currentThread())
}
}
//3.3.執行5次循環
dispatch_group_async(group, queue) { () -> Void in
for _ in 0..<5 {
NSLog("group-03 - %@", NSThread.currentThread())
}
}
//4.都完成后會自動通知
dispatch_group_notify(group, dispatch_get_main_queue()) { () -> Void in
NSLog("完成 - %@", NSThread.currentThread())
}
打印結果
2017-04-10 03:40:34.277 test[12540:3319271] group-03 - <NSThread: 0x7f9772536f00>{number = 3, name = (null)}
2017-04-10 03:40:34.277 test[12540:3319146] group-02 - <NSThread: 0x7f977240ba60>{number = 1, name = main}
2017-04-10 03:40:34.277 test[12540:3319146] group-02 - <NSThread: 0x7f977240ba60>{number = 1, name = main}
2017-04-10 03:40:34.277 test[12540:3319271] group-03 - <NSThread: 0x7f9772536f00>{number = 3, name = (null)}
2017-04-10 03:40:34.278 test[12540:3319146] group-02 - <NSThread: 0x7f977240ba60>{number = 1, name = main}
2017-04-10 03:40:34.278 test[12540:3319271] group-03 - <NSThread: 0x7f9772536f00>{number = 3, name = (null)}
2017-04-10 03:40:34.278 test[12540:3319271] group-03 - <NSThread: 0x7f9772536f00>{number = 3, name = (null)}
2017-04-10 03:40:34.278 test[12540:3319146] group-02 - <NSThread: 0x7f977240ba60>{number = 1, name = main}
2017-04-10 03:40:34.277 test[12540:3319273] group-01 - <NSThread: 0x7f977272e8d0>{number = 2, name = (null)}
2017-04-10 03:40:34.278 test[12540:3319271] group-03 - <NSThread: 0x7f9772536f00>{number = 3, name = (null)}
2017-04-10 03:40:34.278 test[12540:3319146] group-02 - <NSThread: 0x7f977240ba60>{number = 1, name = main}
2017-04-10 03:40:34.278 test[12540:3319273] group-01 - <NSThread: 0x7f977272e8d0>{number = 2, name = (null)}
2017-04-10 03:40:34.278 test[12540:3319146] group-02 - <NSThread: 0x7f977240ba60>{number = 1, name = main}
2017-04-10 03:40:34.278 test[12540:3319273] group-01 - <NSThread: 0x7f977272e8d0>{number = 2, name = (null)}
2017-04-10 03:40:34.279 test[12540:3319146] group-02 - <NSThread: 0x7f977240ba60>{number = 1, name = main}
2017-04-10 03:40:34.279 test[12540:3319146] group-02 - <NSThread: 0x7f977240ba60>{number = 1, name = main}
2017-04-10 03:40:34.279 test[12540:3319146] 完成 - <NSThread: 0x7f977240ba60>{number = 1, name = main}
這些就是 GCD 的基本功能,只要你想象力夠豐富,你可以組合出更好的用法。
補充:
func dispatch_barrier_async(_ queue: dispatch_queue_t, _ block: dispatch_block_t):
這個方法重點是你傳入的queue
,當你傳入的queue
是通過DISPATCH_QUEUE_CONCURRENT
參數自己創建的queue
時,這個方法會阻塞這個queue
(注意是阻塞queue
,而不是阻塞當前線程),一直等到這個queue
中排在它前面的任務都執行完成后才會開始執行自己,自己執行完畢后,才會取消阻塞,使這個queue
中排在它后面的任務繼續執行。
如果你傳入的是其他的queue
, 那么它就和dispatch_async
一樣了。func dispatch_barrier_sync(_ queue: dispatch_queue_t, _ block: dispatch_block_t):
這個方法的使用和上一個一樣,傳入 自定義的并發隊列(DISPATCH_QUEUE_CONCURRENT
),它和上一個方法一樣的阻塞queue
,不同的是 這個方法還會 阻塞當前線程。
如果你傳入的是其他的queue
, 那么它就和dispatch_sync
一樣了。