【发布时间】:2021-09-15 03:55:29
【问题描述】:
我们的应用目前使用NSOperation(Swift 中的Operation)来管理一系列网络请求和数据解析。
需要在队列中的所有5个操作都完成后执行一些代码,通常使用GCD组实现。
DispatchQueue.global().async {
(0...5).forEach(){
self.queue.addOperation(CustomOperation(value: $0))
}
self.queue.waitUntilAllOperationsAreFinished()
print("All Tasks Done")
}
问题是 NSOperation 实例而不是 deinit 直到所有 5 个操作完成,这导致内存释放比预期的要晚。
如果queue.waitUntilAllOperationsAreFinished 被删除,实例将立即变为deinit。
我们添加了自动释放池来避免它。但是在使用waitUntilAllOperationsAreFinished 时是否可以立即将NSOperation 实例化为deinit?
用waitUntilAllOperationsAreFinished 打印
Begin Task 5
Begin Task 4
Begin Task 3
Begin Task 2
Begin Task 1
Begin Task 0
Finish Task 0
Finish Task 1
Finish Task 2
Finish Task 3
Finish Task 4
Finish Task 5
deinit 0
deinit 1
deinit 2
deinit 3
deinit 4
deinit 5
All Tasks Done
打印不带waitUntilAllOperationsAreFinished
All Tasks Done
Begin Task 0
Begin Task 1
Begin Task 4
Begin Task 3
Begin Task 5
Finish Task 0
Begin Task 2
deinit 0
Finish Task 1
deinit 1
Finish Task 2
deinit 2
Finish Task 3
deinit 3
Finish Task 4
deinit 4
Finish Task 5
deinit 5
自定义操作。
class CustomOperation: Operation {
public enum State {
case ready
case running
case finished
}
private var state: State = .ready
override var isAsynchronous: Bool { return true }
override open var isExecuting: Bool { state == .running }
override open var isFinished: Bool { state == .finished }
var value: Int = 0
init(value: Int) {
super.init()
self.value = value
}
override func main() {
print("Begin Task \(value)")
DispatchQueue.global().asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(value)) {
print("Finish Task \(self.value)")
self.finish()
}
}
func finish() {
willChangeValue(forKey: "isExecuting")
willChangeValue(forKey: "isFinished")
state = .finished
didChangeValue(forKey: "isFinished")
didChangeValue(forKey: "isExecuting")
}
deinit {
print("deinit")
}
}
【问题讨论】:
-
与手头的问题无关,但这不是线程安全的。正如the docs 所说,“如果您在子类中实现自定义方法,例如自定义数据访问器,您还必须确保这些方法是线程安全的。”另外,请注意,您永远不会将
state设置为.running(我通常在start中设置,但您也可以在main中设置)。此外,我们通常也有cancelled的状态。但这些都与手头的问题无关,只是一个友好的观察。 -
FWIW,而不是
waitUntilAllOperationsAreFinished(阻塞有限数量的工作线程之一),我们将使用完成操作(w 依赖项)或屏障操作。它们都遇到了与这里相同的问题,但它们比waitUntilAllOperationsAreFinished更好(没有阻塞的线程,不需要将其分派到全局队列等)。在回答您的问题时,我们只需让finish函数从内存中释放任何对象。该操作本身占用的内存非常少,因此将您的内存消耗与释放操作时分离。
标签: swift nsoperationqueue nsoperation