多个 NSManagedObjectContexts - 防止竞争条件和死锁
Posted
技术标签:
【中文标题】多个 NSManagedObjectContexts - 防止竞争条件和死锁【英文标题】:Multiple NSManagedObjectContexts - preventing race conditions and deadlocks 【发布时间】:2014-12-02 22:54:09 【问题描述】:我已经阅读了大量关于后台核心数据进程的博客,但我还没有更深入地了解如何最好地管理许多同时触发的 BG 核心数据任务并在未定义的情况下通知主线程 MOC时间。
我知道每个 NSThread
应该有 1 个 NSManagedObjectContext
,并且通过订阅 NSManagedObjectContextDidSaveNotification
以及使用 [context performBlock
我可以完成一些不错的异步任务。
也就是说,我正在异步运行很多任务,我不能 100% 知道一些任务何时会重叠,并且我观察到了以下形式的竞争条件......
BG MOC 1 开始执行任务 BG MOC 2 开始执行任务 BG MOC 2 完成任务并发送保存通知 BG MOC 1 完成任务并随后擦除 BG MOC 2s 更改我的总体问题是如何解决多个 MOC 中的竞争条件?
如果正确的行为是每个线程有 1 个 MOC。我可以创建一个 NSThread ivar 并将我的所有核心数据工作放在上面吗?这样我就可以拥有一个与自身同步工作的 MOC?
我读过 NSLock 可能是避免同时从多个线程访问某些代码的解决方案。但我不知道我应该锁定什么?保存上下文方法?持久存储(似乎使多线程毫无意义)?
最后,我可以标记/编号/命名我的 MOC 吗?这样,如果我知道其他任务正在运行,我可以存储通知并按照它们被实例化的顺序处理它们,以确保没有数据被覆盖?
【问题讨论】:
【参考方案1】:建议每个线程一个 MOC。有例外,但一般规则仍然成立。不要创建 NSThread 对象。只是不要。太痛苦了。而是使用块或 NSOperation 实例。它们更容易摸索并保护您免受很多痛苦。
不要对 Core Data 使用锁。如果使用得当,Core Data 会进行自己的锁定,如果你在周围乱扔锁,就会导致问题。理想情况下,您应该永远在现代 Objective-C 中自己调用 lock。
除了具有 ivar 或属性引用之外,您不能命名 MOC。你也不应该需要。
使用 Core Data 进行多线程的最简洁方法如下:
您有一个主线程/UI MOC。那是你唯一的真理来源。您的 UI 会从中获取数据并写入数据。 任何后台进程都在 NSOperation 或类似结构中完成。您在此构造中创建一个 MOC,它是主上下文的 子 上下文。 保存子项时,更改将合并到父项(即 UI MOC)。 设置适合您的主 MOC 的合并策略。如果您认为需要针对不同情况制定不同的政策,那么您应该重新审视自己的工作方式。理想情况下,每个后台进程都应该是一个数据孤岛,可以独立运行而不会与另一个进程发生冲突。如果您有冲突,那么这是您需要在业务逻辑中解决的合并问题。
如果您遇到两个后台操作将命中同一条数据的情况,那么您应该按顺序运行它们,而不是并行运行。对相同数据的并行编辑是等待发生的痛苦,不要这样做。
您可以通过使用NSOperationQueue
实例来控制事情是顺序的还是并行的。
遵循这些规则,您将不会遇到竞争条件或死锁。
【讨论】:
很好的答案,非常感谢。我没有在我的实现中使用NSOperation
/ NSOperationQueue
,所以我将从那里开始。很高兴对我所有狡猾的想法都坚决反对。
“NSOperation 或类似的构造。你创建一个 MOC 而不是这个构造”应该是“这个构造的内部”吗?
我假设使用 GCD 算作“类似构造”,只要每个 MOC 及其对象只能从其自己的串行队列访问,一切都很好,不是吗? NSOperationQueue.
你说 GCD 是一个“相似的结构”是正确的。然而,NSOperations 有几个好处,包括可维护性(单独的类文件更容易维护)和取消操作的能力。还有其他好处,但这是一个较长的讨论。
"如果您遇到两个后台操作将命中同一条数据的情况,那么您应该按顺序运行它们,而不是并行运行。对同一数据进行并行编辑是等待发生的痛苦,不要这样做。”伟大的洞察力。正在尝试实现这方面。以上是关于多个 NSManagedObjectContexts - 防止竞争条件和死锁的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:如何将 NSManagedObjectContext 传递到多个视图模型中
NSManagedObjectContext 通过通知中心问题在多个线程上保存/合并