2

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

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

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

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

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

4

2 回答 2

2

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

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

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

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

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

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

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

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

于 2012-10-12T04:09:23.743 回答
2

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

请参阅我的这篇文章关于一些指针: http: //www.cocoanetics.com/2012/07/multi-context-coredata/

于 2012-10-12T11:38:32.537 回答