Swift版本 1.多執行緒開發 -- CGD的簡單使用
在我們實際開發中, 有難免會遇到一些問題, 比如我要從網上下載一張圖片進行修改, 這裡就涉及到執行緒的問題了, 還有就是我們平常使用的下載工具: 迅雷, QQ旋風之類的, 它們可以進行同時下載, 也可以一個一個的來下載, 在這裡我們稱之為同步和非同步, 顧名思義, 所謂的同步就是所有檔案一起下載, 非同步就是把需要下載的檔案一個個排好隊來下載.
1.基本概念
在開始說多執行緒之前, 我們要知道兩樣東西, 一個是程序, 一個是執行緒:
程序: 正在進行中的程式就叫做程序, 負責程式執行的記憶體分配, 每一個程序都有自己獨立的虛擬記憶體空間.
執行緒: 執行緒是程序中一個獨立的執行路徑(控制單元), 一個程序中至少包含一條執行緒(主執行緒), 可以將耗時的操作或者執行放到另一個執行緒裡.
說白了, 程序就是為程式分配記憶體的, 而執行緒就是用來控制程式程式碼的實際執行.
舉個例子, 我們的程式執行, 都是按照程式碼從上往下的執行, 但如果遇到需要下載圖片的時候, 它就會卡在這裡, 等待圖片下載完成才會執行下一步, 這樣子就不符合我們的實際體驗了, 所以我們會把下載圖片放到子執行緒裡去操作, 等到下載完成之後才傳回給主執行緒, 這就是多執行緒的好處, 既不會影響主執行緒的執行, 又可以完成下載圖片的任務.
提示:
1.dispatch_async 非同步操作,會併發執⾏,無法確定任務的執⾏順序
2.dispatch_sync 同步操作,會依次順序執⾏,能夠決定任務的執行順序
PS: 執行緒是有限的, 不可以無休止的增加, 而主執行緒的大小隻有1MB, 子執行緒都是512KB.
2.GCD佇列
序列佇列: 佇列中的任務只會順序執⾏
func gcdDemo1() {
// 將操作放在佇列中
// 在 C 語言函式中, 定義型別, 絕大多數都是以_t或者ref 結尾
// 使用序列佇列的非同步任務, 可以節省資源, 新建執行緒是需要有資源消耗的, 不能無休止的去新建執行緒
// 應用案例:
// 從網上下載圖片
// 濾鏡(高光, 紅眼...)
var q: dispatch_queue_t = dispatch_queue_create("com.cain.gcdDemo1", DISPATCH_QUEUE_SERIAL)
let i = 0
for i in 0...10 {
dispatch_async(q, { () -> Void in
println(NSThread.currentThread())
})
}
// 非 ARC 開發時, 一定要 release
// dispatch_release(q);
// 序列佇列的同步任務, 也會在主執行緒中執行
// 在實際開發中, 極少人用
// 面試又可能會用到
for i in 0...9 {
// 同步任務, 順序執行
dispatch_async(q, { () -> Void in
println("\(NSThread.currentThread()) - \(i)")
})
}
}
並行佇列: 佇列中的任務通常會併發執⾏
func gcdDemo2() {
// 特點: 沒有順序, 程式設計師不可控
// 應用場景: 併發執行的, 沒有先後順序
// 並行佇列容易出錯, 並行佇列建立的子執行緒數量同樣是不可控
var q: dispatch_queue_t = dispatch_queue_create("com.cain.gcdDemo2", DISPATCH_QUEUE_CONCURRENT)
for i in 0...9 {
// 同步任務
dispatch_sync(q, { () -> Void in
println("\(NSThread.currentThread()) - \(i)")
})
// 非同步任務
dispatch_async(q, { () -> Void in
// [NSThread currentThread] 可以在開發中跟蹤當前的執行緒.
// number = 1表示主執行緒
// number = 2或者其他, 表示子執行緒, 這裡是2, 所以是第2個子執行緒
println("\(NSThread.currentThread()) - \(i)")
})
}
}
全域性佇列
func gcdDemo3() {
// 全域性佇列與並行佇列的區別
// 1< 不需要建立, 直接GET就可以使用
// 2< 兩個佇列的執行效果相同
// 3< 全域性佇列沒有名稱, 除錯時無法確認準確佇列
var q: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
for i in 0...9 {
// 非同步任務
dispatch_async(q, { () -> Void in
println("\(NSThread.currentThread()) - \(i)")
})
// 同步任務
dispatch_sync(q, { () -> Void in
println("\(NSThread.currentThread()) - \(i)")
})
}
}
主執行緒佇列
func gcdDemo4() {
var q = dispatch_get_main_queue()
for i in 0...9 {
// 非同步任務, 併發執行, 保持隊形的
dispatch_async(q, { () -> Void in
println("\(NSThread.currentThread()) - \(i)")
});
// 同步任務
// 注意, 在主執行緒佇列中不可以使用同步任務, 否則會造成執行緒阻塞
// dispatch_sync(q, { () -> Void in
// println("come here baby!")
// });
}
}
3.GCD總結
串⾏佇列
1.同步任務, 不需要新建執行緒, 非同步任務, 需要⼀個⼦執行緒, 執行緒的建立和回收不需要程式設計師參與!
2.“是最安全的一個選擇”串⾏行佇列只能建立!
並行佇列
1.同步任務, 不需要建立執行緒並行佇列, 非同步任務, 有多少個任務, 就開N個執行緒執⾏行 無論什麼佇列和什麼任務, 執行緒的建立和回收不需要程式設計師參與.
2.執行緒的建立回收⼯作是由佇列負責的 “併發”程式設計, 為了讓程式設計師從負責的執行緒控制中解脫出來! 只需要⾯對佇列和任務!
GCD的好處
1.通過GCD, 開發者不⽤再直接跟執行緒打交道, 只需要向佇列中新增程式碼塊即可.
2.GCD在後端管理著⼀個執行緒池, GCD不僅決定著程式碼塊將在哪個執行緒被執⾏, 它還根據可用的系統資源對這些執行緒進⾏管理. 從而讓開發者從執行緒管理的工作中解放出來, 通過集中的管理執行緒, 緩解大量執行緒被建立的問題.
3.使⽤用GCD, 開發者可以將工作考慮為一個佇列, 而不是一堆執行緒,這種並行的抽象模型更容易掌握和使⽤.
GCD的佇列
1.GCD公開有5個不同的佇列: 運⾏在主執行緒中的主佇列, 3個不同優先順序的後臺佇列, 以及一個優先順序更低的後臺佇列(⽤於 I/O).
2.⾃定義佇列: 串⾏行和並⾏行佇列, ⾃定義佇列⾮常強大,建議在開發中使⽤, 在⾃定義佇列中被排程的所有Block最終都將被放⼊到系統的全域性佇列中和執行緒池中.
提示: 不建議使⽤用不同優先順序的佇列, 因為如果設計不當, 可能會出現優先順序反轉, 即低優先順序的操作阻塞⾼優先順序的操作.
好了, 這次我們就講到這裡, 下次我們繼續~~