1. 程式人生 > >Swift版本 1.多執行緒開發 -- CGD的簡單使用

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最終都將被放⼊到系統的全域性佇列中和執行緒池中.

提示: 不建議使⽤用不同優先順序的佇列, 因為如果設計不當, 可能會出現優先順序反轉, 即低優先順序的操作阻塞⾼優先順序的操作.

好了, 這次我們就講到這裡, 下次我們繼續~~