gpt4 book ai didi

objective-c - waitUntilAllOperationsAreFinished 和 objectWithID

转载 作者:行者123 更新时间:2023-11-30 10:19:51 25 4
gpt4 key购买 nike

更新 我可以确认 objectWithID 可能需要父(或祖 parent 等)上下文的线程来进行一些获取,因此避免使用类似 waitUntilAllOperationsAreFinished

作为一个快速测试,我将子级 moc 的父级指向其祖级,并让子级线程阻塞原始父级。在此设置中,死锁从未发生。但这是一个糟糕的架构,所以我将重新架构。

原始问题

我有两层NSOperationQueue。第一个是 NSOperation 图,其中的操作之间具有一组依赖关系。它们都运行良好,彼此之间没有陷入僵局。在其中一个操作(用于多人的调度程序)中,我将其工作分解为可以在另一个 NSOperationQueue 上运行的更离散的 block 。但是,我仍然希望调度程序在较大的操作被视为完成之前完成其所有计划的创建。为此,一旦我创建了所有 Schedule 操作并将它们添加到 Scheduler 操作队列中,我就会在操作队列上调用 waitUntilAllOperationsAreFinished。这就是我陷入僵局的地方。

我正在使用 Core Data,并且有一个名为 BlockOperationNSBlockOperation 子类,它处理获取父托管对象上下文、创建 PrivateQueueConcurrencyType 子上下文、调用提供的例程使用performBlockAndWait 进行阻止,最后等待父上下文合并更改。这是一些代码...

init(block: (NSManagedObjectContext?) -> Void, withDependencies dependencies: Array<NSOperation>, andParentManagedObjectContext parentManagedObjectContext: NSManagedObjectContext?) {
self.privateContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)

super.init()

self.queuePriority = NSOperationQueuePriority.Normal
addExecutionBlock({
if (parentManagedObjectContext != nil) {
self.parentContext = parentManagedObjectContext!

self.privateContext.parentContext = parentManagedObjectContext!

self.privateContext.performBlockAndWait({ () -> Void in
block(self.privateContext)
})

self.parentContext!.performBlockAndWait({ () -> Void in
var error: NSError?
self.parentContext!.save(&error)
})
}
})

for operation in dependencies {
addDependency(operation)
}
}

这对我来说已经非常有效了。但现在我想阻塞调用线程,直到其上的操作队列完成其所有操作。像这样...

for group in groups {
let groupId = group.objectID
let scheduleOperation = BlockOperation(
block: { (managedObjectContext: NSManagedObjectContext?) -> Void in
ScheduleOperation.scheduleGroupId(groupId, inManagedObjectContext: managedObjectContext!)
},
withDependencies: [],
andParentManagedObjectContext: managedObjectContext)
scheduleOperationQueue.addOperation(scheduleOperation)
}

scheduleOperationQueue.waitUntilAllOperationsAreFinished()

...该线程卡在最后一行(显然)。但我们从未看到其他线程取得任何超过某一点的进展。暂停调试器,我看到排队操作被卡住的地方。在 ScheduleOperation 的 init 方法中,我们使用提供的 id 获取组。 (ScheduleOperation.scheduleGroupId 调用此 init)

convenience init(groupId: NSManagedObjectID, inManagedObjectContext managedObjectContext: NSManagedObjectContext) {

let group = managedObjectContext.objectWithID(groupId) as Group
...

objectWithID 是否需要在与其父 moc 关联的“父”线程上执行代码,从而导致死锁?我的方法是否还有其他原因可能导致此问题?

注意:虽然我写的是 Swift,但我添加了 Objective-C 作为标签,因为我觉得这不是特定于语言的问题,而是特定于框架的问题。

最佳答案

一般来说,不会指定将在哪个线程上调用 objectWithID,它是一个实现细节。我过去遇到过一些核心数据死锁问题(尽管在不同的情况下),并且我发现当您调用 NSManagedObjectContext 上的方法时,框架会在内部进行一些锁定。所以是的,我认为这可能会导致僵局。

除了重新设计你的架构之外我没有什么建议,也许它可以简化一点。请记住,您已经有一个与上下文关联的专用串行队列,这保证了将按指定的顺序调用操作。因此,您可以在所有 ScheduleOperation 实例之间共享相同的上下文。将scheduleOperationQueue.maxConcurrentOperationsCount 设置为1,以便操作将依次执行。并且不要阻塞调用线程,而是在最后一个操作完成时调用完成处理程序(您可以使用 oepration 的 completionBlock)。

关于objective-c - waitUntilAllOperationsAreFinished 和 objectWithID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27584789/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com