GCD
Grand Central Dispatch
,是蘋果為多核的并行運算提出的解決方案胁勺,所以會自動合理地利用更多的CPU
內(nèi)核(比如雙核怀愧、四核),最重要的是它會自動管理線程的生命周期(創(chuàng)建線程挫酿、調(diào)度任務(wù)构眯、銷毀線程),完全不需要我們管理早龟,我們只需要告訴干什么就行惫霸。同時它使用的也是 c語言
,不過由于使用了 Block
(Swift
里叫做閉包
)葱弟,使得使用起來更加方便壹店,而且靈活。所以基本上大家都使用GCD
這套方案芝加。
任務(wù)和隊列
在GCD
中硅卢,加入了兩個非常重要的概念: 任務(wù) 和 隊列。
任務(wù):即操作藏杖,你想要干什么将塑,說白了就是一段代碼,在
GCD
中就是一個Block
蝌麸,所以添加任務(wù)十分方便点寥。任務(wù)有兩種執(zhí)行方式:** 同步執(zhí)行 **和 異步執(zhí)行,他們之間的區(qū)別是是否會創(chuàng)建新的線程
来吩。
同步(sync)
和異步(async)
的主要區(qū)別在于會不會阻塞當前線程敢辩,直到Block
中的任務(wù)執(zhí)行完畢!
如果是同步(sync)
操作弟疆,它會阻塞當前線程并等待Block
中的任務(wù)執(zhí)行完畢戚长,然后當前線程才會繼續(xù)往下運行。
如果是異步(async)
操作怠苔,當前線程會直接往下執(zhí)行同廉,它不會阻塞當前線程。隊列:用于存放任務(wù)嘀略。一共有兩種隊列恤溶, 串行隊列 和 并行隊列。
串行隊列 中的任務(wù)會根據(jù)隊列的定義FIFO
的執(zhí)行帜羊,一個接一個的先進先出的進行執(zhí)行咒程。
并行隊列 放到并行隊列的任務(wù),GCD
也會FIFO
的取出來讼育,但不同的是帐姻,它取出來一個就會放到別的線程稠集,然后再取出來一個又放到另一個的線程。這樣由于取的動作很快饥瓷,忽略不計剥纷,看起來,所有的任務(wù)都是一起執(zhí)行的呢铆。不過需要注意晦鞋,GCD
會根據(jù)系統(tǒng)資源控制并行的數(shù)量,所以如果任務(wù)很多棺克,它并不會讓所有任務(wù)同時執(zhí)行悠垛。
創(chuàng)建隊列
- 主隊列:這是一個特殊的 串行隊列蒙畴。什么是主隊列邢锯,大家都知道吧,它用于刷新 UI候生,任何需要刷新 UI 的工作都要在主隊列執(zhí)行纱皆,所以一般耗時的任務(wù)都要放到別的線程執(zhí)行湾趾。
//OBJECTIVE-C
dispatch_queue_t queue = dispatch_get_main_queue();
//SWIFT
let queue = dispatch_get_main_queue()
-
自己創(chuàng)建的隊列:自己可以創(chuàng)建 串行隊列, 也可以創(chuàng)建 并行隊列。 看下面的代碼派草,它有兩個參數(shù)搀缠,其中第一個參數(shù)是
標識符
,用于DEBUG
的時候標識唯一的隊列澳眷,可以為空胡嘿。大家可以看xcode的文檔查看參數(shù)意義,第二個才是最重要的钳踊。
第二個參數(shù)用來表示創(chuàng)建的隊列是串行
的還是并行
的,傳入DISPATCH_QUEUE_SERIAL
或NULL
表示創(chuàng)建串行隊列勿侯。傳入DISPATCH_QUEUE_CONCURRENT
表示創(chuàng)建并行隊列拓瞪。
//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)
- 全局并行隊列:只要是并行任務(wù)一般都加入到這個隊列。這是系統(tǒng)提供的一個并發(fā)隊列助琐。
//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)
創(chuàng)建任務(wù)
-
同步任務(wù):會阻塞當前線程 (SYNC)
OBJECTIVE-C
dispatch_sync(<#queue#>, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
});
SWIFT
dispatch_sync(<#queue#>, { () -> Void in
//code here
println(NSThread.currentThread())
})
-
異步任務(wù):不會阻塞當前線程 (ASYNC)
OBJECTIVE-C
dispatch_async(<#queue#>, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
});
SWIFT
dispatch_async(<#queue#>, { () -> Void in
//code here
println(NSThread.currentThread())
})
隊列組
隊列組可以將很多隊列添加到一個組里祭埂,這樣做的好處是,當這個組里所有的任務(wù)都執(zhí)行完了兵钮,隊列組會通過一個方法通知我們蛆橡。下面是使用方法,這是一個很實用的功能掘譬。
OBJECTIVE-C
//1.創(chuàng)建隊列組
dispatch_group_t group = dispatch_group_create();
//2.創(chuàng)建隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//3.多次使用隊列組的方法執(zhí)行任務(wù), 只有異步方法
//3.1.執(zhí)行3次循環(huán)
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 3; i++) {
NSLog(@"group-01 - %@", [NSThread currentThread]);
}
});
//3.2.主隊列執(zhí)行8次循環(huán)
dispatch_group_async(group, dispatch_get_main_queue(), ^{
for (NSInteger i = 0; i < 8; i++) {
NSLog(@"group-02 - %@", [NSThread currentThread]);
}
});
//3.3.執(zhí)行5次循環(huán)
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.創(chuàng)建隊列組
let group = dispatch_group_create()
//2.創(chuàng)建隊列
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//3.多次使用隊列組的方法執(zhí)行任務(wù), 只有異步方法
//3.1.執(zhí)行3次循環(huán)
dispatch_group_async(group, queue) { () -> Void in
for _ in 0..<3 {
NSLog("group-01 - %@", NSThread.currentThread())
}
}
//3.2.主隊列執(zhí)行8次循環(huán)
dispatch_group_async(group, dispatch_get_main_queue()) { () -> Void in
for _ in 0..<8 {
NSLog("group-02 - %@", NSThread.currentThread())
}
}
//3.3.執(zhí)行5次循環(huán)
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())
}
打印結(jié)果
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
參數(shù)自己創(chuàng)建的queue
時睦焕,這個方法會阻塞這個queue
(注意是阻塞queue
藐握,而不是阻塞當前線程),一直等到這個queue
中排在它前面的任務(wù)都執(zhí)行完成后才會開始執(zhí)行自己垃喊,自己執(zhí)行完畢后猾普,才會取消阻塞,使這個queue
中排在它后面的任務(wù)繼續(xù)執(zhí)行本谜。
如果你傳入的是其他的queue
, 那么它就和dispatch_async
一樣了初家。func dispatch_barrier_sync(_ queue: dispatch_queue_t, _ block: dispatch_block_t):
這個方法的使用和上一個一樣,傳入 自定義的并發(fā)隊列(DISPATCH_QUEUE_CONCURRENT
)乌助,它和上一個方法一樣的阻塞queue
笤成,不同的是 這個方法還會 阻塞當前線程。
如果你傳入的是其他的queue
, 那么它就和dispatch_sync
一樣了眷茁。