好吧,首先,如果你想要最大的性能,如果你真的需要,不要使用 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 绑定和更高的带宽。
一种将坏和好的连接考虑在内的可扩展方法,努力保持低内存占用并最大限度地提高性能,但很难实现 - 并且是一项具有挑战性的编程任务。玩得开心!;)