iOS并发:如何使用OperationQueue代替barrier?
iOS concurrent: how to use OperationQueue instead of barrier?
学习OperationQueue
时,是否可以使用OperationQueue
代替gcd barrier
?
情况如下:
upload 3 images , then upload other 3 images
与 barrier
、gcd
完美搭配
func workFlow(){
let queue = DispatchQueue(label: "test.concurrent.queue", qos: .background, attributes: .concurrent, autoreleaseFrequency: .workItem)
queue.async {
self.uploadImg(idx: "A_0")
}
queue.async {
Thread.sleep(forTimeInterval: 2)
self.uploadImg(idx: "A_1")
}
queue.async {
self.uploadImg(idx: "A_2")
}
queue.async(qos: queue.qos, flags: .barrier) {
print("group A done")
}
print("A: should not be hanged")
queue.async {
self.uploadImg(idx: "B_0")
}
queue.async {
self.uploadImg(idx: "B_1")
}
queue.async {
self.uploadImg(idx: "B_2")
}
queue.async(qos: queue.qos, flags: .barrier) {
print("group B done")
}
print("B: should not be hanged")
}
func uploadImg(idx info: String){
Thread.sleep(forTimeInterval: 1)
print("img \(info) uploaded")
}
与OperationQueue
相比,这里有一点小瑕疵
主队列被挂起,检查打印
"A/B: should not be hanged"
lazy var uploadQueue: OperationQueue = {
var queue = OperationQueue()
queue.name = "upload queue"
queue.maxConcurrentOperationCount = 5
return queue
}()
func workFlow(){
let one = BlockOperation {
self.uploadImg(idx: "A_0")
}
let two = BlockOperation {
Thread.sleep(forTimeInterval: 3)
self.uploadImg(idx: "A_1")
}
let three = BlockOperation {
self.uploadImg(idx: "A_2")
}
uploadQueue.addOperations([one, two, three], waitUntilFinished: true)
print("A: should not be hanged")
uploadQueue.addOperation {
print("group A done")
}
let four = BlockOperation {
self.uploadImg(idx: "B_0")
}
let five = BlockOperation {
self.uploadImg(idx: "B_1")
}
let six = BlockOperation {
self.uploadImg(idx: "B_2")
}
uploadQueue.addOperations([four, five, six], waitUntilFinished: true)
print("B: should not be hanged")
uploadQueue.addOperation {
print("group B done")
}
}
如何使用 OperationQueue
做得更好?
如果不希望加入队列的操作阻塞当前线程,waitUntilFinished
必须是false
。但是如果你设置为true
,它会阻塞当前线程,直到添加的操作完成。
显然,如果你不等待,它不会阻塞主线程,但你也会失去屏障行为。但是 iOS 13 和 macOS 10.15 引入了 addBarrierBlock
。如果你真的需要障碍并且必须支持更早的 OS 版本,那么你将不得不使用依赖项。但是,如果您之前使用 GCD 屏障只是为了限制并发程度,那么 maxConcurrentOperationCount
可能会使屏障变得毫无意义。这完全取决于您为什么要对这些 uploads/downloads 使用障碍。 (看到 upload/download 队列的障碍有点不寻常,因为它会降低效率。)
How to do it better with OperationQueue
?
我假设 uploadImg
同步下载图像。我会将其重构为自己的 Operation
子类,它执行必要的 Operation
KVO,例如 。这包含了运行中的下载任务,但您也可以对上传或数据任务执行相同的操作(尽管数据任务对内存的影响要大得多)。
但始终建议避免同步网络请求,以 (a) 确保不占用工作线程; (b) 使请求可取消。
学习OperationQueue
时,是否可以使用OperationQueue
代替gcd barrier
?
情况如下:
upload 3 images , then upload other 3 images
与 barrier
、gcd
完美搭配
func workFlow(){
let queue = DispatchQueue(label: "test.concurrent.queue", qos: .background, attributes: .concurrent, autoreleaseFrequency: .workItem)
queue.async {
self.uploadImg(idx: "A_0")
}
queue.async {
Thread.sleep(forTimeInterval: 2)
self.uploadImg(idx: "A_1")
}
queue.async {
self.uploadImg(idx: "A_2")
}
queue.async(qos: queue.qos, flags: .barrier) {
print("group A done")
}
print("A: should not be hanged")
queue.async {
self.uploadImg(idx: "B_0")
}
queue.async {
self.uploadImg(idx: "B_1")
}
queue.async {
self.uploadImg(idx: "B_2")
}
queue.async(qos: queue.qos, flags: .barrier) {
print("group B done")
}
print("B: should not be hanged")
}
func uploadImg(idx info: String){
Thread.sleep(forTimeInterval: 1)
print("img \(info) uploaded")
}
与OperationQueue
相比,这里有一点小瑕疵
主队列被挂起,检查打印
"A/B: should not be hanged"
lazy var uploadQueue: OperationQueue = {
var queue = OperationQueue()
queue.name = "upload queue"
queue.maxConcurrentOperationCount = 5
return queue
}()
func workFlow(){
let one = BlockOperation {
self.uploadImg(idx: "A_0")
}
let two = BlockOperation {
Thread.sleep(forTimeInterval: 3)
self.uploadImg(idx: "A_1")
}
let three = BlockOperation {
self.uploadImg(idx: "A_2")
}
uploadQueue.addOperations([one, two, three], waitUntilFinished: true)
print("A: should not be hanged")
uploadQueue.addOperation {
print("group A done")
}
let four = BlockOperation {
self.uploadImg(idx: "B_0")
}
let five = BlockOperation {
self.uploadImg(idx: "B_1")
}
let six = BlockOperation {
self.uploadImg(idx: "B_2")
}
uploadQueue.addOperations([four, five, six], waitUntilFinished: true)
print("B: should not be hanged")
uploadQueue.addOperation {
print("group B done")
}
}
如何使用 OperationQueue
做得更好?
如果不希望加入队列的操作阻塞当前线程,waitUntilFinished
必须是false
。但是如果你设置为true
,它会阻塞当前线程,直到添加的操作完成。
显然,如果你不等待,它不会阻塞主线程,但你也会失去屏障行为。但是 iOS 13 和 macOS 10.15 引入了 addBarrierBlock
。如果你真的需要障碍并且必须支持更早的 OS 版本,那么你将不得不使用依赖项。但是,如果您之前使用 GCD 屏障只是为了限制并发程度,那么 maxConcurrentOperationCount
可能会使屏障变得毫无意义。这完全取决于您为什么要对这些 uploads/downloads 使用障碍。 (看到 upload/download 队列的障碍有点不寻常,因为它会降低效率。)
How to do it better with
OperationQueue
?
我假设 uploadImg
同步下载图像。我会将其重构为自己的 Operation
子类,它执行必要的 Operation
KVO,例如
但始终建议避免同步网络请求,以 (a) 确保不占用工作线程; (b) 使请求可取消。