我有一些操作需要同步运行。我试着关注这个链接,但对我的情况来说还不够清楚。
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:的一个很好的理由
- 将您的任务定义为
Publisher
s - 使用
flatMap
将它们链接起来,可以选择将输出从上一个传递到下一个 - 使用
switchToLatest
重新启动整个程序,并在前一个程序仍在运行时取消它(如果有的话( - 使用订阅服务器上的
cancel
取消整个事件