Swift-启动/停止同步操作队列



我有一些操作需要同步运行。我试着关注这个链接,但对我的情况来说还不够清楚。

op2在op1完成之前不会启动,op3在op2完成之前也不会启动,但在此期间,我需要能够停止任何操作并重新启动。例如,如果op2正在运行,我知道它不能停止,但无论出于什么原因,我都需要能够阻止op3执行,因为op1已经重新启动。我该怎么做?

这是一个非常简单的例子,实际的代码是更复杂的

var queue1 = OperationQueue()
var queue2 = OperationQueue()
var queue3 = OperationQueue()

var operation1: BlockOperation?
var operation2: BlockOperation?
var operation3: BlockOperation?
// a DispatchGroup has finished running now it's time to start the operations ...
dispatchGroup.notify(queue: .global(qos: .background)) { [weak self] in
DispatchQueue.main.async { [weak self] in
self?.runFirstFunc()
}
}
func runFirstFunc() {
var count = 0
let num in arr  {
count += num
}
// now that the loop is finished start the second func but there is a possibility something may happen in the first that should prevent the second func from running
runSecondFunc(count: count)
}
func runSecondFunc(count: Int) {
do {
try ...
// if the do-try is successful do something with count then start thirdFunc but there is a possibility something may happen in the second func that should prevent the third func from running
runThirdFunc()
} catch {
return
}
}
func runThirdFunc() {
// this is the final operation, once it hits here I know it can't be stopped even if I have to restart op1 again but that is fine
}

你说:

op2直到op1完成才开始,op3直到op2完成才开始。。。

如果使用OperationQueue,您可以通过创建三个操作来实现这一点,并将op1定义为op2的依赖项,将op2定义为op3的依赖项。

。。。但在那段时间里,我需要能够停止任何操作,重新开始。

如果使用OperationQueue,如果要停止已添加到队列中的所有操作,请调用cancelAllOperations

例如,如果op2正在运行,我知道它无法停止。。。

好吧,这取决于op2在做什么。如果它在循环中旋转进行计算,那么,是的,它可以在操作中期被取消。您只需检查isCancelled,如果是,请停止有问题的操作。或者,如果是网络请求(或其他可取消的请求(,您也可以覆盖cancel方法并取消任务。这取决于手术在做什么。

。。。但无论出于何种原因,我都需要能够阻止op3执行,因为op1已经重新启动。

当然,在取消了cancelAllOperations的所有操作后,您可以将三个新操作(及其相关的依赖项(重新添加到队列中。

这是一个未经测试的实现,它允许在任何任务(重复(执行其子任务时取消。

如果第二个任务失败/抛出,它会自动从第一个任务重新启动。

如果用户手动停止/启动,最后一个运行中的任务将退出执行(尽快(。

注意:您必须根据自己的实施情况来处理[weak self]部分。

import Foundation
class TestWorker {
let workerQueue = DispatchQueue.global(qos: .utility)
var currentWorkItem: DispatchWorkItem?

func start() {
self.performTask { self.performTask1() }
}

func stop() {
currentWorkItem?.cancel()
}

func performTask(block: @escaping (() -> Void)) {
let workItem = DispatchWorkItem(block: block)
self.currentWorkItem = workItem
workerQueue.async(execute: workItem)
}

func performTask1() {
guard let workItem = self.currentWorkItem else { return }
func subtask(index: Int) {}
for i in 0..<100 {
if workItem.isCancelled { return }
subtask(index: i)
}
self.performTask { self.performTask2() }
}

func performTask2() {
guard let workItem = self.currentWorkItem else { return }
func subtask(index: Int) throws {}
for i in 0..<100 {
if workItem.isCancelled { return }
do { try subtask(index: i) }
catch { 
self.start()
return
}
}
self.performTask { self.performTask3() }
}

func performTask3() {
guard let workItem = self.currentWorkItem else { return }
func subtask(index: Int) {}
for i in 0..<100 {
if workItem.isCancelled { return }
subtask(index: i)
}
/// Done
}
}

也许,这是研究Swift Combine:的一个很好的理由

  • 将您的任务定义为Publishers
  • 使用flatMap将它们链接起来,可以选择将输出从上一个传递到下一个
  • 使用switchToLatest重新启动整个程序,并在前一个程序仍在运行时取消它(如果有的话(
  • 使用订阅服务器上的cancel取消整个事件

最新更新