先来一个不安全的版本
//: 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 方法,这个方法来封装我们的读操作,读操作的发起方需要在调用读方法的时候能直接拿到返回值,而不是在异步回调里面获取
三 时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())
}
}