为什么Android开发者应该使用FlatBuffers替代JSON?

1758762091 8年前
   <p>你可能会问,既然我们已经有很标准的JSON以及转换库比如GSON和Jackson,为什么还要使用新的工具呢?</p>    <p>不妨先试一下FlatBuffers,然后你就会发现它比JSON快得多。</p>    <h2>FlatBuffers是什么?</h2>    <p><a href="/misc/goto?guid=4959675105872476966" rel="nofollow,noindex">FlatBuffers</a> 是一个高效的跨平台序列化类库,可以在C++、C#、C、Go、Java、JavaScript、PHP和Python中使用。是 <strong>Google</strong> 开发的,是为了应用在游戏开发,以及其他注重性能的应用上。</p>    <p>为什么要使用FlatBuffers?</p>    <ul>     <li> <p>不需要解析/拆包就可以访问序列化数据— FlatBuffers与其他库不同之处就在于它使用二进制缓冲文件来表示层次数据,这样它们就可以被直接访问而不需解析与拆包,同时还支持数据结构进化(前进、后退兼容性)。</p> </li>     <li> <p>内存高效速度快— 访问数据时只需要访问内存中的缓冲区。它不需要多余的内存分配(至少在C++是这样,其他语言中可能会有变动)。FlatBuffers还适合配合mmap或数据流使用,只需要缓冲区的一部分存储在内存中。访问时速度接近原结构访问,只有一点延迟(一种虚函数表vtable),是为了允许格式升级以及可选字段。FlatBuffers适合那些花费了大量时间和空间(内存分配)来访问和构建序列化数据的项目,比如游戏以及其他对表现敏感的应用。可以参考这里的 <a href="/misc/goto?guid=4959675105961485696" rel="nofollow,noindex">基准</a> 。</p> </li>     <li> <p>灵活— 由于有可选字段,你不但有很强的升级和回退兼容性(对于历史悠久的游戏尤其重要,不用为了每个版本升级所有数据),在选择要存储哪些数据以及设计数据结构时也很自由。</p> </li>     <li> <p>轻量的code footprint— FlatBuffers只需要很少量的生成代码,以及一个表示最小依赖的很小的头文件,很容易集成。细节上可以看上面的基准页。</p> </li>     <li> <p>强类型— 编译时报错,而不需要自己写重复的容易出错的运行时检查。它可以自动生成有用的代码。</p> </li>     <li> <p>使用方便— 生成的C++代码允许精简访问与构建代码。还有可选的用于实现图表解析、类似JSON的运行时字符串展示等功能的方法。(后者比JSON解析库更快,内存效率更高)</p> </li>     <li> <p>代码跨平台且没有依赖— C++代码可以运行在任何近代的gcc/clang和VS2010上。同时还有用于测试和范例的构建文件(Android中.mk文件,其他平台是cmake文件)。</p> </li>    </ul>    <p>都有谁使用FlatBuffers?</p>    <ul>     <li> <p><a href="/misc/goto?guid=4959675106047675825" rel="nofollow,noindex"><strong>BobbleApp</strong> </a> ,印度第一贴图App。我们在BobbleApp中使用FlatBuffers后App的性能明显增强。</p> </li>     <li> <p><a href="/misc/goto?guid=4958329674997436949" rel="nofollow,noindex">Cocos2d-x</a> ,第一开源移动游戏引擎,使用FlatBuffers来序列化所有的游戏数据。</p> </li>     <li> <p>非死book使用FlatBuffers在Android App中进行客户端服务端的沟通。他们写了一篇 <a href="/misc/goto?guid=4959642687230880427" rel="nofollow,noindex">文章</a> 来描述FlatBuffers是如何加速加载内容的。</p> </li>     <li> <p>Google的 <a href="/misc/goto?guid=4959675106180817546" rel="nofollow,noindex">Fun Propulsion Labs</a> 在他们所有的库和游戏中大量使用FlatBuffers。</p> </li>    </ul>    <p>App性能有多大提高?</p>    <ul>     <li> <p>解析速度解析一个20KB的JSON流(这差不多是BobbleApp的返回大小)需要35ms,超过了UI刷新间隔也就是16.6ms。如果解析JSON的话,我们就在滑动时就会因为要从磁盘加载缓存而导致掉帧(视觉上的卡顿)。</p> </li>     <li> <p>解析器初始化一个JSON解析器需要先构建字段映射再进行解析,这会花100ms到200ms,很明显的拖缓App启动时间。</p> </li>     <li> <p>垃圾回收在解析JSON时创建了很多小对象,在我们的试验中,解析20kb的JSON流时,要分配大约100kb的瞬时存储,对Java内存回收造成很大压力。</p> </li>    </ul>    <p>FlatBuffers vs JSON</p>    <p>我尝试使用FlatBuffers和JSON解析4mb的JSON文件。</p>    <p>FlatBuffers花了1-5ms,JSON花了大约2000ms。在使用FlatBuffers期间Android App中没有GC,而在使用JSON时发生了很多次GC。在使用JSON时UI完全卡住,所以真实使用时只能在后台线程进行解析。</p>    <p><img src="https://simg.open-open.com/show/3bf0957bf49ddc2fa5382db08c7b2e74.jpg"></p>    <p>如何使用FlatBuffer呢?</p>    <p>我在我的GitHub中写了一个 <a href="/misc/goto?guid=4959675106264883528" rel="nofollow,noindex">示例</a> ,里面手把手教你如何使用FlatBuffer。</p>    <p> </p>    <p><a href="/misc/goto?guid=4959675106355647300">阅读原文</a></p>    <p> </p>