CoreData和RestKit的性能,同时导入非常大的数据集
我正在使用RestKit来获取各种terminal上的JSON数据(在iOS平台上)。
在这个问题上,有几个问题指向了同样的方向:
使用CoreData在iPhone上导入大型数据集
但是我的问题还是不同的,因为我知道,如果JSON文件变得太大,我不得不把它切成块。 我会去做!
在RestKit中用CoreData完成的导入究竟如何?
似乎有一个父/子上下文设置,这是非常低效的,当在最短的时间内导入大数据集 (可能一次启动 – 没有批次/懒惰导入!!! )。
在这里看到一个来自Florian Kugler的在CoreData(Stacks)
我的问题是:我可以设置一个不同的上下文,除了父/子上下文设置已经与RestKit
和运行RKManagedObjectRequestOperation
导入完全asynchronous和另一个上下文。 然后将上下文合并到mainContext中以获取…
我真的想坚持使用CoreData,而不是切换到普通的SQLite,从CoreData
和RestKit
组合中获得最可能的性能。
我很高兴你的专业答案。 也许布雷克也可以直接回答我这个问题。
那么,首先,如果你想要最大的性能,如果你真的需要 ,不要使用RestKit,不要使用AFNetworking,也不要使用NSJSONSerialization
。 它们都受到deviseselect的困扰,处理大型数据集的时候效果不佳,而且您的目标是保持适中的内存足迹和高性能。
您应该有一个非常大的单个JSON(可能是JSON数组,其元素是JSON对象)作为单个连接的主体,以获得卓越的性能。 或者,您可以使用自定义传输格式在一个连接中发送多个JSON(例如,由“空白”分隔的一系列JSON对象)。
拥有大量的连接肯定是缓慢的。
当您努力实现最快的性能时,您应该同时下载,parsingJSON,创build表示并将其保存到持久性存储中。
注意:
当所有这些都是平行进行的时候,你对连接错误特别容易受到攻击,保持一致和逻辑正确的数据集可能成为一个挑战。 因此,如果您的连接遭受质量差和频繁中断,您可能首先下载并保存JSON文件到一个临时文件(也支持HTTP范围标题的机会暂停和恢复下载)。 当然,你的performance会下降 – 但在这种情况下,无论如何你都无法做到这一点。
所以,当你的目标是最高性能的时候,你应该利用所有CPU的能力,并行运行,因为它是有意义的 – 当连接速度很快的时候尤其如此。
JSONparsing器也应该能够parsing包含在一个NSData
对象中的“块”(部分JSON),因为这是我们从connection:didReceiveData:
获得的connection:didReceiveData:
当您收到JSON数据时,您需要将其“映射”为合适的表示forms。 通常,已知的JSONparsing器创build一个“基础表示”。 但是,更快的方法是直接从JSON中创build最终所需types的对象。 这需要一个“SAX风格的API” – 这基本上是一个parsing器的简化版本,它向委托或客户端发送“parsing事件”,例如“得到JSON-Array开始”或“得到JSON布尔假”等,自定义代码,它接收这些事件并即时构build所需的对象。
这一切都需要一个具有在NSJSONSerialization
找不到的function的JSONparsing器:SAX风格的API,“块parsing”或parsinginput,这是一系列JSON文档。
为了最大限度地利用CPU,磁盘和networking,可以将“任务”划分为CPU绑定,I / O绑定和networking绑定操作,并创build尽可能多的并且以并行方式运行。 这些任务基本上都是asynchronous运行,接受input,处理input,并产生一个输出,它是下一个asynchronous任务的input。 第一个任务在完成时通知下一个任务,例如通过完成处理程序(块),并通过parameter passing它的输出。
处理JSON数据的传入“块”,即parsing和创build表示 ,是一个CPU绑定操作。 然而,这通常是相当快的,我不认为通过并发队列来分配所有可用的CPU上的CPU限制任务是不值得的。
处理JSON数据的传入“块”基本上可以用两种方法来实现,同样有利有弊:
部分JSON数据asynchronous处理
当你在connection:didReceiveData:
得到一个“块”时connection:didReceiveData:
你可以asynchronous调度到一个不同的队列上进行处理(即parsing和创build表示),而不是在委托上运行。
优点:代理立即返回,从而不会阻塞委托线程,从而最快地读取传入的networking数据和适度的小型networking缓冲区。 连接在最短的时间内完成。
缺点:如果与接收数据相比,处理速度较慢,则可以在等待在串行调度队列中执行的块中排队大量的NSData
对象。 这将保持为每个NSData
对象分配的内存 – 系统RAM可能最终会耗尽,你可能会得到内存警告或崩溃,除非你采取适当的行动。
同步处理部分JSON数据
当接收到一个JSON块时,parsing器将相对于委托的线程被同步调用。
优点:与接收数据相比,这样可以避免数据处理速度较慢时的内存问题。 但是,这最终可能会阻止从networking读取数据(一旦内部接收缓冲区已满)。
缺点:如果处理速度慢,内部networking缓冲区变满,则会增加连接活动的时间,从而增加连接断开的可能性。
这两种方法都从一个快速的parsing器/表示生成器中受益,并且需要一个可以将JSON的“块”处理为NSData
对象的parsing器,并在完成表示时asynchronous通知客户端。 可选地,它也应该具有“SAX风格”API。 有两个第三方的JSONparsing器,我知道满足这些要求:
jsonlite和这个
JPJson
两者都非常快(比JSONKit和NSJSONSerialization更快),支持SAX风格parsing,并可以将JSON作为NSData
对象处理。 JPJson还可以处理包含多个JSON的文件。
(披露:我是JPJson的作者)
创build表示时,下一步是创build并初始化托pipe对象(除非parsing器直接生成pipe理对象),并将对象保存到持久性存储中。 这是一个I / O和CPU绑定操作 – 但是当使用SSD存储时可能会有更多的CPU绑定。 我会安排这个过程到一个单独的队列,并检查它是如何与其他CPU绑定操作一起工作的。 networking的速度取决于networking的速度,networking在更高的带宽下变得更加CPU绑定。
考虑到糟糕和良好的连接的可扩展的方法,努力保持低内存足迹和最大化性能,但是很难实现 – 而且是一个具有挑战性的编程任务。 玩的开心! ;)