主佇列&主執行緒

d_d發表於2018-10-28

目的

探究主佇列和主執行緒關係。

過程

1.主佇列任務是否一定在主執行緒執行?

    DispatchQueue.global().async {
        DispatchQueue.main.async {
            let currentThread = Thread.current
            print(currentThread.isMainThread) //列印為true
        }
    }
複製程式碼

結論:所以主佇列只會在主執行緒中執行。

2.主執行緒是否只執行主佇列的任務?

DispatchQueue.global().sync {
    let currentThread = Thread.current
    print(currentThread.isMainThread) //列印為true
}
複製程式碼

結論:主執行緒還有可能會執行其他佇列的任務。這是為了避免執行緒切換對效能的消耗。因為CPU的暫存器只有一套,多執行緒執行時系統勢必會不斷排程切換。這樣每個執行緒需要一個上下文來記錄當前執行狀態。這樣新執行緒被執行時首先將上下文寫入暫存器,執行結束暫存器重新寫入上下文,如此不斷切換才避免了多執行緒的資料混亂。

使用

RxSwift的判斷方式:

extension DispatchQueue {
    private static var token: DispatchSpecificKey<()> = {
        let key = DispatchSpecificKey<()>()
        DispatchQueue.main.setSpecific(key: key, value: ())
        return key
    }()

    static var isMain: Bool {
        return DispatchQueue.getSpecific(key: token) != nil
    }
}
複製程式碼

Kingfisher中為了提高效能當在主佇列主執行緒中時就直接執行block。因為如果只判斷是主佇列就執行有可能此時CPU正在處理其他執行緒任務,如果只判斷主執行緒那麼此時執行的任務有可能是其他佇列的,並不能保證block新增到執行的佇列。

extension DispatchQueue {
    // This method will dispatch the `block` to self.
    // If `self` is the main queue, and current thread is main thread, the block
    // will be invoked immediately instead of being dispatched.
    func safeAsync(_ block: @escaping ()->()) {
        if self === DispatchQueue.main && Thread.isMainThread {
            block()
        } else {
            async { block() }
        }
    }
}
複製程式碼

參考

深入iOS系統底層之CPU暫存器介紹

相關文章