swift 实现一个高效线程安全的Array

先来一个不安全的版本

//: FROM  https://www.anuomob.com

import UIKit
import PlaygroundSupport
//不希望主线程执行完毕就结束
PlaygroundPage.current.needsIndefiniteExecution = true

var array = Array(0...10000)
func getLastItem()->Int?{
    var temp:Int? = nil
    if array.count>0{
        temp = array[array.count-1]
    }
    return temp
}
      
func removeLastItem(){
    array.removeLast()
}


let queue = DispatchQueue(label: "q1", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)

let queue2 = DispatchQueue(label: "q2", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
queue.async {
    for _ in 0 ..< 10000{
        removeLastItem()
    }
}

queue2.async {
   for _ in 0 ..< 10000{
    if let item = getLastItem(){
        print(item)
    }
      }
}

为啥会出现这个问题 因为一个线程在操作获取最后一个元素 一个线程在删除最后一个元素

下面用下锁 lock

//: FROM  https://www.anuomob.com

import UIKit
import PlaygroundSupport
let lock = NSLock()
//不希望主线程执行完毕就结束
PlaygroundPage.current.needsIndefiniteExecution = true

var array = Array(0...10000)
func getLastItem()->Int?{
    lock.lock()
    var temp:Int? = nil
    if array.count>0{
        temp = array[array.count-1]
    }
    lock.unlock()
    return temp
}
      
func removeLastItem(){
    lock.lock()
    array.removeLast()
     lock.unlock()
}


let queue = DispatchQueue(label: "q1", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)

let queue2 = DispatchQueue(label: "q2", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
queue.async {
    for _ in 0 ..< 10000{
        removeLastItem()
    }
}

queue2.async {
   for _ in 0 ..< 10000{
    if let item = getLastItem(){
        print(item)
    }
      }
}

这个虽然实现了我们效果

但是效率确存在争议

如果在一段时间内只有读操作,我们时不需要加锁的,而上述NSLock的方式则仍然强制每一次读操作都加锁等待,对性能造成不小影响,尤其时我们对数组的读操作远远多于写操作的时候,这个性能的影响就会相当客观,那么怎么解决这一问题呢?

一个队列两个方法

首先是并行队列,既然我们要保持多线程环境并操作的优势,那我们肯定要选择并行队列。

二是sync 方法,这个方法来封装我们的读操作,读操作的发起方需要在调用读方法的时候能直接拿到返回值,而不是在异步回调里面获取

扫描二维码关注公众号,回复: 11651769 查看本文章

三 时async方法使用barrier flag 这个方法来封装我们的写操作,这个方法祈祷一个栅栏作用,它等待所有位于barrier async函数之前的操作执行完毕后执行,并且在barrier async 函数执行之后,barrier async 函数之后的操作才会得到执行

//: FROM  https://www.anuomob.com

import UIKit
import PlaygroundSupport
let lock = NSLock()
//不希望主线程执行完毕就结束
PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue(label: "q1", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)

let queue2 = DispatchQueue(label: "q2", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)

let arrayQueue  = DispatchQueue(label: "q3", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)


var array = Array(0...10000)
func getLastItem()->Int{
    return arrayQueue.sync  { ()-> Int in
        if array.count>0{
            return array[array.count-1]
             
        }
        return -1
    }
}
      
func removeLastItem(){
    let workItem = DispatchWorkItem(qos: DispatchQoS.default, flags: DispatchWorkItemFlags.barrier, block: {
        array.removeLast()
    })
    arrayQueue.async(execute: workItem)
}


queue.async {
    for _ in 0 ..< 10000{
        removeLastItem()
    }
}

queue2.async {
   for _ in 0 ..< 10000{
    print(getLastItem())
      }
}

猜你喜欢

转载自blog.csdn.net/mp624183768/article/details/108365557