5

我正在使用 RestKit 在各种端点(在 iOS 平台上)上获取 JSON 数据。

关于 SO 有几个问题指向与那个相同的方向:

使用 CoreData 在 iPhone 上导入大型数据集

但我的问题仍然是一个不同的问题,因为我知道,如果 JSON 文件变得太大,我必须将它切成块。我会去做的!

RestKit 中 CoreData 的导入到底是如何完成的。
似乎有一个父/子上下文设置,在尽可能短的时间内导入大型数据集时效率非常低(可能在启动时一次全部 -没有批量/延迟导入!!!)。

请参阅 Florian Kugler 的一篇关于 CoreData (Stacks) 中的高性能导入的帖子

我的问题是:我可以设置一个不同的上下文,除了已经设置的父/子上下文并在另一个上下文上RestKit运行RKManagedObjectRequestOperation完全异步的导入。然后将上下文合并到 mainContext 以获取...

我真的想坚持使用 CoreData 而不是切换到普通的 SQLite,从组合CoreDataRestKit.

我很高兴看到你的专业回答。也许布莱克也可以直接回答我这个问题。

4

1 回答 1

11

好吧,首先,如果你想要最大的性能,如果你真的需要,不要使用 RestKit,不要使用 AFNetworking,不要使用NSJSONSerialization. 如果您的目标是保持适度的内存占用和高性能,它们都受到设计选择的影响,这些选择在处理大型数据集时效果不佳。

您应该有一个非常大的单个 JSON(可能是一个 JSON 数组,其元素是 JSON 对象)作为单个连接的主体,以获得卓越的性能。或者,您可以使用自定义传输格式,在一个连接中发送多个 JSON(例如,一系列 JSON 对象,由“空白”分隔)。

拥有大量连接肯定很慢。

当您努力实现最快的性能时,您应该同时下载、解析 JSON、创建表示并将其保存到持久存储中。

笔记:

并行执行所有这些操作时,您特别容易受到连接错误的影响,并且保持一致且逻辑正确的数据集可能会成为挑战。因此,如果您的连接质量不佳且经常中断,您可以先下载 JSON 文件并将其保存到临时文件(还支持 HTTP 范围标头,以便有机会暂停和恢复下载)。当然,你的表现会下降——但在这种情况下,无论如何你都无法让它变得更快。

同样,当您的目标是最大性能时,您应该利用所有 CPU 功能,即尽可能多地并行运行 - 特别是在连接速度快的情况下。

JSON 解析器还应该能够解析NSData对象中包含的“块”——即部分 JSON——,因为这是我们从connection:didReceiveData:.

当您收到 JSON 数据时,您需要将其“映射”为合适的表示形式。通常,已知的 JSON 解析器会创建一个“基础表示”。然而,更快的方法是直接从 JSON 创建最终所需的对象类型。这需要一个“SAX 风格的 API”——它基本上是一个简化版本的解析器,它向委托或客户端发送“解析事件”——例如“get JSON-Array begin”或“got JSON Boolean False”等。接收这些事件并动态构建所需对象的自定义代码。

这一切都需要一个 JSON 解析器,它具有您在以下方面找不到的功能NSJSONSerialization:SAX 样式 API、“块解析”或解析一系列 JSON 文档的输入。

为了最大限度地利用 CPU、磁盘和网络,您将“任务”划分为 CPU 密集型、I/O 密集型和网络密集型操作,并在系统合理的情况下创建尽可能多的并行运行. 这些任务基本上都是异步运行的,接受一个输入,处理输入,并产生一个输出,作为下一个异步任务的输入。第一个任务在完成时通知下一个任务,例如通过完成处理程序(块),并通过参数传递其输出。

处理传入的 JSON 数据“块”,即解析和创建表示,是一个 CPU 密集型操作。然而,这通常非常快,而且我认为通过并发队列在所有可用 CPU 上分派这些 CPU 密集型任务是不值得的。

处理传入的 JSON 数据“块”基本上可以通过两种方法实现,各有利弊:

异步处理部分 JSON 数据

当您获得“块”时,connection:didReceiveData:您可以将其异步安排到不同的队列中以进行处理(即解析和创建表示),该队列在与委托不同的线程上运行。

优点:委托立即返回,因此不会阻塞委托线程,这反过来会导致传入网络数据的最快读取和适度小的网络缓冲区。连接在尽可能短的时间内完成。

NSData缺点:如果与接收数据相比处理速度较慢,您可能会在块中排队等待在串行调度队列中执行的大量对象。这将保留为每个NSData对象分配的内存 - 系统 RAM 最终可能会耗尽,除非您采取适当的措施,否则您可能会收到内存警告或崩溃。

同步处理部分 JSON 数据

当接收到一段 JSON 时,解析器将相对于委托的线程同步调用。

优点:与接收数据相比,当数据处理速度较慢时,这避免了内存问题。但是,这最终可能会停止从网络读取数据(一旦内部接收缓冲区已满)。

缺点:如果处理速度慢并且内部网络缓冲区已满,这将增加连接处于活动状态的时间,从而增加连接断开的可能性。

这两种方法都受益于快速解析器/表示生成器,并且需要一个解析器,该解析器可以将 JSON 的“块”作为NSData对象处理,并在完成表示时异步通知客户端。或者,它还应该有一个“SAX 风格”的 API。我知道有两个第三方 JSON 解析器可以满足这些要求:

jsonlite 和这个

JPJson

两者都非常快(比 JSONKit 和 NSJSONSerialization 更快),支持 SAX 样式解析,并且可以将 JSON 块作为NSData对象处理。JPJson 还可以处理包含多个 JSON 的文件。

(披露:我是JPJson的作者)

创建表示后,下一步是创建和初始化托管对象(除非解析器直接生成管理对象)并将对象保存到持久存储中。这是一个 I/O 和 CPU 受限的操作 - 但在使用 SSD 存储时可能更多的 CPU 受限。我会将这个进程安排到一个单独的队列中,并检查它是如何与其他 CPU 绑定操作一起工作的。根据网络的速度,网络变得更多的 CPU 绑定和更高的带宽。

一种将坏和好的连接考虑在内的可扩展方法,努力保持低内存占用并最大限度地提高性能,但很难实现 - 并且是一项具有挑战性的编程任务。玩得开心!;)

于 2013-07-26T13:02:41.567 回答