排查核心数据死锁?

Posted

技术标签:

【中文标题】排查核心数据死锁?【英文标题】:Troubleshoot Core Data Deadlocks? 【发布时间】:2012-10-12 02:36:07 【问题描述】:

我有一个 ios 应用程序,它从 Web 服务中提取用户数据并将其保存到支持 sqlite 的核心数据存储中。虽然这也在进行中,但我正在获取用户头像的 url,并在每个图像的下载可用时将图像本地保存到核心数据中。

这些都在各自的线程上执行,具有自己的托管对象上下文,但具有相同的共享持久存储协调器。

当只有几个项目被拉下时,这很有效,但是当我们接近 100 个左右的项目时,我在初始加载数据时经常遇到死锁。当我暂停调试器时,我看到不同的线程通常都在等待 executeFetchRequest。

我在我的方案中打开了 sql 调试,根据控制台输出,获取完成,但线程永远不会继续。

我还可以使用或查看什么来检查这些死锁的原因或如何防止这些死锁发生?

【问题讨论】:

我想分享的一件事是,如果你在 xcode 中调试时遇到这种死锁(我经常这样做),你可以暂停调试器并查看通常有用的堆栈跟踪(你会看到哪个线程挂在什么函数中)。 【参考方案1】:

确保将数据库更改一起批量更改。每次更改后无需调用 saveContext。相反,在每十几次更改后保存在临时后台上下文中可能就足够了。

请看我这篇文章的一些指点:http://www.cocoanetics.com/2012/07/multi-context-coredata/

【讨论】:

这篇关于使用异步保存的父/子视图控制器的文章真的很有帮助。【参考方案2】:

要回答您的确切问题:“我还可以使用或查看什么来检查这些死锁的原因或如何防止这些死锁发生?”,我只能用一些非常笼统的想法来回答因为你要解决的问题很难:

从您认为可能发生锁定的任何地方添加 NSLog 语句。我发现使用NSLog(@"%s ...YOUR DEBUG STATEMENT", __PRETTY_FUNCTION__) 可以帮助您准确识别正在调用的函数以及正在从哪个队列执行它。

如果我们超越了可用工具的问题(基本上没有什么用处),那么我会留下一些关于如何调试您描述的系统的建议:

作为背景知识:我已经构建了平滑滚动的 UITableViews,其中包含 2000 多个动态下载和显示的可变高度单元格,其中包含绝对不包含由于数据处理或绘图而导致的抖动或延迟的图像。该系统最初是使用 CoreData 设计的,但最终我们直接使用 SQLite 来解决您在多线程和并行性方面遇到的问题。我并不是在提倡切换到 SQLite——这是我们在内部做出的一个决定,目的是提高速度并减少本地数据库中的不一致性。我将此作为我回答的上下文。

首先我会仔细研究您对 Grand Central Dispatch 的使用情况。如果您使用任何 dispatch_sync 调用,请确保它们不会出现在阻塞操作线程的链中。我这样做最初是为了确保多个线程不会同时访问一个托管对象上下文,并且在调试几个小时后才发现问题。这些可能会偷偷摸摸,因为 dispatch_sync 调用可能深入到其他函数调用的函数中。

我最终使用了一个事务系统(非常 SQL-y),它为单个查询/更新动态创建队列,以确保不会同时发生太多操作。我还有一个完全不同的系统,它将使用单独的串行读取队列来快速读取数据库。如果可能,该队列的 MOC 将从其他 MOC 镜像。这很重,而且相对来说非常慢。由于系统主要在后台线程上处理,因此与用户隔离。

CoreData 通常很难多线程。 SQLite 稍微简单一些,但您必须围绕它构建许多特定于应用程序的架构才能使其可用。

如果您想发布有关您的系统的更多详细信息,我可以提供更具体的帮助。我希望这对您有所帮助。

【讨论】:

以上是关于排查核心数据死锁?的主要内容,如果未能解决你的问题,请参考以下文章

mysql 死锁排查

Mysql 死锁排查过程

记录一次Mysql死锁排查过程

记录一次Mysql死锁排查过程

记录一次 Mysql 死锁排查过程

记录一次MySQL死锁排查过程