线程安全存取器GCDSafeAccessor

2021-07-13  本文已影响0人  Jason1226

数据的读写一般容易引发几个问题:

  1. 在主线程中大量数据读写容易阻塞主线程,造成UI卡住。
  2. 读操作和写操作同时执行,或多个写操作同时执行,容易引发并发问题。
    读写锁的说明参考:https://www.jianshu.com/p/a3a9b9460ab8

因此设计一个高效的线程安全存取器很有必要。

class GCDSafeAccessor: NSObject {

    let qos: DispatchQoS
    lazy var queue = DispatchQueue(label: "gcd_safe_accessor", qos: qos, attributes: .concurrent)
 
    init(qos: DispatchQoS = .default) {
        self.qos = qos
        super.init()
    }
    
    // 小数据写入可以在主线程同步执行
    func safeReadSync<T>(_ callback: @escaping () -> T?) -> T? {
        var data: T?
        queue.sync {
            data = callback()
        }
        return data
    }
    // 大数据写入需要在子线程异步进行,避免主线程卡住
    func safeReadAsync(_ callback: @escaping () -> Void) {
        queue.async(execute: callback)
    }
    
    func safeWriteAsync(_ callback: @escaping () -> Void) {
        queue.async(flags: .barrier, execute: callback)
    }
}

使用方式:

    var dict: [String: String] = ["key": "value"]

        // 当前线程同步读取数据方式1
        _ = accessor.safeReadSync {
            let value = self.dict["key"]
        }

        // 当前线程同步读取数据方式2
        let value: String? = accessor.safeReadSync {
            let value = self.dict["key"]
            return value
        }

        // 子线程异步读取数据
        accessor.safeReadAsync {
            let value = self.dict["key"]
        }
        
        // 子线程异步写数据
        accessor.safeWriteAsync {
            self.dict["key"] = "value"
        }

GCDSafeAccessor 提供同步和异步两种方式读取数据,可针对大数据或者同时大量读操作选择异步方式。同步读取数据也提供两种回调方式,方式1 读取数据在闭包内返回,方式 2读取的数据作为接口返回值返回,可根据代码结构选择不同方式。
线程安全方面,如果对读和写同时加上相同锁,则效率不高,因为多个读操作不需要加锁。因此,异步读操作使用并发队列让多个读操作可以并发执行;写操作则使用barrier来实现与读操作的互斥,并且能让多个写操作同步进行。

上一篇 下一篇

猜你喜欢

热点阅读