孙广东   2015.7.4

http://www.open-open.com/lib/view/open1441004786315.html

虽然FB的反序列化超级快,但是数据大小还是蛮大的(可能的原因是不需要解析,直接访问binary buffer,所以不能对数据进行压缩),带来的传输或存储开销,可能会抵过一部分反序列化的时间。感觉上,FB的使用场景上还是很受限,在移动端可能是一个应用场景。

protocol buffer的作者后来又弄了一个Cap'n Proto 但是好像应用场景没有太火

http://google.github.io/flatbuffers/flatbuffers_support.html

提供了对Unity游戏引擎C# 支持!(本身 FlatBuffers 就是 移动平台移动开发 而出的!)

关于Unity的示例代码 必须要学习啊!!!!!!

http://exiin.com/blog/flatbuffers-for-unity-sample-code/

FlatBuffers 是 Google为游戏和移动应用而开发的开源、跨平台的序列化库。支持 C++, Java, C#, Go, Python and JavaScript等语言。中国有5亿智能手机,其中低端设备占多数,在 CPU 和内存都受限的情况下,能否开发出高性能且低内存占用的 Android程序决定了你的应用的用户覆盖率和留存率。

Unity使用 FlatBuffers 作为存储格式移动版)

翻译: http://qiita.com/akerusoft/items/8c10f8a40fee722e6d1b

Unity提供了 PlayerPrefs作为本地的数据存储, 但是速度不是很快!

下面就是一个测试使用FlatBuffers

Unity 5.3.3f1 版本

FlatBuffers 1.3.0版本

运行在 Android /IOS 测试

FlatBuffers序列化保存为二进制。

cocos2dx 游戏数据使用

还应用Facebook上。

FlatBuffers,分为 结构定义 (架构) 和 数据

它要在服务器和客户端可用。

使用 FlatBuffers 的流程

  • 结构定义
  • 自动生成的相应的 语言(java,C# ,java等)文件
  • 序列化/反序列化过程

schema language (aka IDL, Interface DefinitionLanguage)

namespace Data;

file_identifier"MYFI";

unionData
{
MonsterDataV1
}

tableRoot
{
data:Data;
}

tableMonsterDataV1
{
name:string;
hp:uint;
hitRate:float;
speed:uint;
luck:uint;
}

tableMonsterDataV2
{
name:string;
hp:uint;
hitRate:float;
speed:uint;
luck:uint;
defence:uint;
}

root_typeRoot;

来自 <http://qiita.com/akerusoft/items/8c10f8a40fee722e6d1b>

首先是表table MonsterDataV1

假设是在 rpg 游戏中使用的怪物结构

table 字段声明(类型写在 后面)

字段是通过使用 内置类型 进行描述。

除了内置类型,你也可以使用自定义的类型(除了当前table

以下是union的数据。

这是种枚举类型,主要特征table表作为字段。

在本例中是定义的字段 只有 MonsterDataV1

union 中的所有字段占用同一个内存存储(同一时间也只有一个字段有效)。

如果你也可以添加 MonsterDataV2 字段,但数据也只有一个存储。(听起来像一个 c 语言中union

基于这种分析。

"file_identifier"是写在 文件的开头的 文件 ID,您可以使用 4 ASCII 字符 (字节 4-7)。

它是可能要检查服务器发送数据,等等......

升级注意事项

应用程序或游戏,要进行数据升级,当一项新功能被增加应用程序

但是 schema 有一定的局限性。

  1. 应该不会删除字段,如果数据已经在使用
  2. 不更改声明字段的顺序 (新数据在后面追加就行)

升级的Demo

小的是升级,将向表中添加字段。

之前的MonsterDataV1声明:

table MonsterDataV1
{
name:string;
hp:uint;
hitRate:float;
speed:uint;
luck:uint;
}

添加新的字段:

table MonsterDataV1
{
name:string;
hp:uint;
hitRate:float;
speed:uint;
luck:uint; (deprecated)
hoge1:[ubyte];
hoge2:bool;
hoge3:int;
hoge4:long;
hoge5:long; (deprecated)
hoge6:long;
hoge7:long;
hoge8:long; (deprecated)
hoge9:long;
}

union中添加新的 table类型!!!!!

unionData
{
MonsterDataV1,
MonsterDataV2
}
程序的输出

Flatc 可执行文件程序的输出。

Windows 版本是 exe 在github页上的窗体。

对于一个 c# 文件生成用下面的命令。

flatc.exe -o OUTPUT_PATH -n--gen-onefile inputfile.fbs

"OUTPUT_PATH" 请设置路径输出。

要输出一个 c# 文件参数 '-n'

"--gen-onefile"生成 cs 文件时将被输出到一个单独的文件。

您声明数据定义schema文件的名称是 "inputfile.fbs"(所以schema对文件名和后缀名美没有任何限制吧!)

或者直至这样写: flatc -n schemaTemplate.txt --gen-onefile

要导入到Unity的运行时文件

运行 FlatBuffers 项目将生成的Dll 导入到Unity的尝试

官方github DL 。

http://blog.csdn.net/u010019717

在脚本文件中的序列化/反序列化

要反序列化demo github.

在 Test1 test2 序列化反序列化过程中的执行。

ButtonCreate.cs

stringpath = Path.Combine(Application.persistentDataPath, DataName.FILE_NAME);

if(File.Exists(path))
File.Delete(path);

FlatBufferBuilderbuilder = new FlatBufferBuilder(1);

intoffestData;
Data.Data dataType;

Offset<Data.MonsterDataV1>data = Data.MonsterDataV1.CreateMonsterDataV1(builder,builder.CreateString(name), hp, hitRate, speed, luck);
offestData = data.Value;
dataType = Data.Data.MonsterDataV1;

Data.Root.StartRoot(builder);
Data.Root.AddDataType(builder,dataType);
Data.Root.AddData(builder,offestData);
Offset<Data.Root> endOffset =Data.Root.EndRoot(builder);

Data.Root.FinishRootBuffer(builder,endOffset);

bytes =builder.SizedByteArray();

File.WriteAllBytes(path,bytes);

反序列化过程:

ButtonLoad.cs

stringpath = Path.Combine(Application.persistentDataPath, DataName.FILE_NAME);

ByteBufferbuffer = new ByteBuffer(File.ReadAllBytes(path));

Data.Rootroot = Data.Root.GetRootAsRoot(buffer);

Data.DatadataType = root.DataType;

switch(dataType)
{
caseData.Data.MonsterDataV1:
Data.MonsterDataV1 monsterV1= root.GetData<Data.MonsterDataV1>(new Data.MonsterDataV1());

if(monsterV1 == null)
{
Debug.LogError("Failed load monster data version1.");
return;
}

textVersion.text= "Version1";

if(Encoding.Default != Encoding.UTF8)
textName.text =Encoding.Default.GetString(Encoding.Convert(Encoding.UTF8, Encoding.Default,Encoding.UTF8.GetBytes(monsterV1.Name)));
else
textName.text =monsterV1.Name;
textHp.text =monsterV1.Hp.ToString();
textHitRate.text =monsterV1.HitRate.ToString();
textSpeed.text =monsterV1.Speed.ToString();
textLuck.text =monsterV1.Luck.ToString();
textDefence.text = "Nodata";
break;
}

每种类型的反序列化过程中的过滤器在union中定义的类型。

这意味着的消息传递时你重置数据定义,应该用来读取数据。

测试代码在 github 上的有一些不同。

github 上的代码 执行加密过程。

(加密 / 解密处理,处理时间会消耗更长的时间......)

FlatBuffers 的思想

cocos2dx spine

json 输出数据是spine的加载很慢。

以二进制格式是相当棒的

尝试使用及时研究的利与弊??

Unity中使用 FlatBuffers的案例

翻译自: http://exiin.com/blog/flatbuffers-for-unity-sample-code/

1-第一步下载编译器"flatc"和"FlatBuffers.dll"

Flatc.exe 用于将Schema转换成 c#

您可以下载最新的版本 FlatBuffers.dll

https://github.com/google/flatbuffers/releases

首先你要下载最新的 flatc.exe 文件,

然后你进入从Github上下载的源代码:路径下的 "\net\FlatBuffers" 文件夹并打开"FlatBuffers.csproj"

并编译 "FlatBuffers.dll",你需要放到Unity的项目中assets/plugins文件夹内放)。

下一步是创建一个单独的文件夹,放着我的编译器 schema 文件

这里我做了一个批处理脚本 ( compile.bat ) 包含这些行︰

flatc -n SaveSchema.txt--gen-onefile @pause

1

2

flatc -n SaveSchema.txt --gen-onefile

@pause

用于演示,我将使用一个 SaveSchema.txt 文件︰

//example save file

namespaceCompanyNamespaceWhatever;

enumColor : byte { Red = 1, Green, Blue }

unionWeaponClassesOrWhatever { Sword, Gun }

structVec3 {

x:float;

y:float;

z:float;

}

tableGameDataWhatever {

pos:Vec3;

mana:short = 150;

hp:short = 100;

name:string;

inventory:[ubyte];

color:Color = Blue;

weapon:WeaponClassesOrWhatever;

}

tableSword {

damage:int = 10;

distance:short = 5;

}

tableGun {

damage:int = 500;

reloadspeed:short = 2;

}

root_typeGameDataWhatever;

file_identifier"WHAT";

schema 文件定义了要保存的数据的结构体

关于schema 语法的更多信息请阅读这个官方文档页面.

一旦你执行compile.bat,它会创建一个名为"SavedSchema.cs"的新文件

Flatc现在生成的几个类的名称,如"WeaponClassesOrWhatever"

这个C#文件是你整个系统的加载和保存schema的作用

2-下一步,我们如何保存我们的数据?

生成的.cs文件包含的所有类和需保存和加载数据。

到您的项目生成文件的地方

(也请不要忘记将"FlatBuffers.dll"放到您的项目,否则你会看到一些错误)

然后将此代码︰

// Create flatbufferclass

FlatBufferBuilderfbb = new FlatBufferBuilder(1);

// Create our swordfor GameDataWhatever

//------------------------------------------------------

WeaponClassesOrWhateverweaponType = WeaponClassesOrWhatever.Sword;

Sword.StartSword(fbb);

Sword.AddDamage(fbb,123);

Sword.AddDistance(fbb,999);

Offset<Sword>offsetWeapon = Sword.EndSword(fbb);

/*

// For gun uncommentthis one and remove the sword one

WeaponClassesOrWhateverweaponType = WeaponClassesOrWhatever.Gun;

Gun.StartGun(fbb);

Gun.AddDamage(fbb,123);

Gun.AddReloadspeed(fbb,999);

Offset<Gun>offsetWeapon = Gun.EndGun(fbb);

*/

//------------------------------------------------------

// Create stringsfor GameDataWhatever

//------------------------------------------------------

StringOffset cname =fbb.CreateString("Test String ! time : " + DateTime.Now);

//------------------------------------------------------

// CreateGameDataWhatever object we will store string and weapon in

//------------------------------------------------------

GameDataWhatever.StartGameDataWhatever(fbb);

GameDataWhatever.AddName(fbb,cname);

GameDataWhatever.AddPos(fbb,Vec3.CreateVec3(fbb, 1, 2, 1)); // structs can be inserted directly, no need tobe defined earlier

GameDataWhatever.AddColor(fbb,CompanyNamespaceWhatever.Color.Red);

//Store weapon

GameDataWhatever.AddWeaponType(fbb,weaponType);

GameDataWhatever.AddWeapon(fbb,offsetWeapon.Value);

var offset =GameDataWhatever.EndGameDataWhatever(fbb);

//------------------------------------------------------

GameDataWhatever.FinishGameDataWhateverBuffer(fbb,offset);

// Save the datainto "SAVE_FILENAME.whatever" file, name doesn't matter obviously

using (var ms = newMemoryStream(fbb.DataBuffer.Data, fbb.DataBuffer.Position, fbb.Offset)) {

File.WriteAllBytes("SAVE_FILENAME.whatever", ms.ToArray());

Debug.Log("SAVED !");

}

你写你的数据的方式是 顺序依赖.

你总是要由内而外创建项目.

从一切开始该对象包含(如字符串、 数组、 其他对象) 的对象本身。

基本上,如果使用了其他的对象,就要预先设置其他的对象!

所以这里发生的是︰

我们要先创建的weapon string ,因为GameDataWhatever里面使用了他们

储蓄的一部分可以真的很棘手,我劝你读这篇文章有更好的理解如何存储数据。

3-最后,读取文件是小菜一碟。

可以按任何顺序,如果你想要你甚至不需要去通过的所有值,因为flatbuffers 工作像变魔术一样 !

ByteBuffer bb = newByteBuffer(File.ReadAllBytes("SAVE_FILENAME.whatever"));

if(!GameDataWhatever.GameDataWhateverBufferHasIdentifier(bb)) {

throw new Exception("Identifier testfailed, you sure the identifier is identical to the generated schema'sone?");

}

GameDataWhateverdata = GameDataWhatever.GetRootAsGameDataWhatever(bb);

Debug.Log("LOADEDDATA : ");

Debug.Log("NAME: " + data.Name);

Debug.Log("POS: " + data.Pos.X + ", " + data.Pos.Y + ", " +data.Pos.Z);

Debug.Log("COLOR: " + data.Color);

Debug.Log("WEAPONTYPE : " + data.WeaponType);

switch(data.WeaponType) {

case WeaponClassesOrWhatever.Sword:

Sword sword = new Sword();

data.GetWeapon<Sword>(sword);

Debug.Log("SWORD DAMAGE : " + sword.Damage);

break;

case WeaponClassesOrWhatever.Gun:

Gun gun = new Gun();

data.GetWeapon<Gun>(gun);

Debug.Log("GUN RELOAD SPEED : " + gun.Reloadspeed);

break;

default:

break;

}

我们测试了flatbuffers 对所有主要的移动平台 (iOS,Android,亚马逊的操作系统,Windows Phone) 它工作得很好。

4 Unity中的源代码

如果你想示例代码和已编译的flatbuffer 文件 flatc.exe 和 flatbuffers.dll,然后下载此文件︰

FlatBuffersTest.zip

来自 <http://exiin.com/blog/flatbuffers-for-unity-sample-code/>

快速上手

接下来将会简要介绍如何使用FlatBuffers。

  • 首先,为你要进行序列化操作的数据结构编写一个schema文件。在定义数据结构的属性时,你可以使用基本类型(各种长度的整形与浮点型),也可以是一个字符串,一个任意类型的数组,一个自定义的对象,甚至是一个自定义对象的集合(unions)。属性的值都是允许为空的,同时也可以设置默认值,所以这样一来,每个构建的对象可以根据自己的需要设置属性值。
  • 然后,用flatc命令(FlatBuffer的编译器)去生成一个C++头文件(或者生成Java/C#/Go/Python等等其他语言的相关文件),进而通过相应的辅助类文件来构建序列化数据。这个生成的C++头文件(比如 mydata_generated.h)只依赖flatbuffers.h,顺便补充一句,flatbuffers.h里包含了很多核心的函数。
  • 接着,使用FlatBufferBuilder类去构建一个单层级的二进制流数据。通过之前flatc命令生成好的代码以及FlatBufferBuilder的使用,简单的一些函数调用,就可以让你很自如地向二进制流中加入对象。
  • 好了,是时候将生成的二进制数据存起来了!或者,你是在做网络通信,那就它这些数据传输出去吧!
  • 当然,从另一个角度来说,当你获取到二进制数据,要将他解析成对象的时候,你可以将数据指针指向它的根对象,然后你可以在需要的位置方便地将它进行转换,获取你要的属性(object->field())。

开发资源

  • 如何构建编译环境,如何在多平台上运行示例代码.
  • 如何使用编译器.
  • 如何编写一个schema
  • 如何将生成的C++代码加入到你自己程序中
  • 如何将生成的C#/Java代码加入到你自己程序中
  • 如何将生成的Co代码加入到你自己程序中
  • FlatBuffers对平台、语言、特性的支持度
  • Benchmarks数据——看看FlatBuffers的优势
  • FlatBuffers的白皮书
  • FlatBuffers内部结构介绍
  • schema正式语法

网络资源

  • GitHub 库
  • 官方主页
  • FlatBuffers Google 小组
  • FlatBuffers 相关讨论
  • 独立化实现的工具:FlatCC另一个FlatBuffers的解析工具与代码生成器,运行在C上
  • 视频资源:
    • Colt’sDevByte.
    • GDC 2015Lightning Talk.
    • FlatBuffers forGo.
    • Evolution of FlatBuffersvisualization.
  • 其他同仁创作的好文档:
    • FlatBuffers in Go
    • FlatBuffers in Android
    • Parsing JSON to FlatBuffers in Java
    • FlatBuffers in Unity

测试案例

http://blog.csdn.net/u010019717

在Google的Benchmark中,已经明确表明了其性能优势,杠杠的啊!

考虑到其扩语言与轻量级的特性,笔者专门自己做了一些较为贴近生产场景的测试,对比的是开发常用的1.1.41版本的fastjson

贴上代码

FlatBuffer与fastjson的比较

packageflatbuffers.test;

importjava.nio.ByteBuffer;

importjava.util.Arrays;

importcom.alibaba.fastjson.JSONObject;

importflatbuffers.FlatBufferBuilder;

importflatbuffers.schema.Product;

public classBufferCompareTest {

static final long LOOP_COUNT = 5000000;

public static void main(String[] args) {

System.out.println("执行"+LOOP_COUNT+"次解析耗时比较");

//FlatBuffers

byte[] dataByte =buildFlatBuffersByte();

long startFlatBuffers =System.currentTimeMillis();

Product p = null;

for (int i = 0; i < LOOP_COUNT; i++){

p =Product.getRootAsProduct(ByteBuffer.wrap(dataByte));

}

System.out.println("FlatBuffers :" + (System.currentTimeMillis() - startFlatBuffers)+"ms");

//JSON

String jsonStr ="{\"marketable\":\"true\",\"costPrice\":15000,\"imgUrl\":\"http://img2.bbgstatic.com/14e2a07cbd5_2_8f02bdb34427ec107124fd1576287310_800x800.jpeg\",\"productBn\":\"MG120394938912345\",\"productId\":123456,\"productName\":\"德国爱他美Aptamil Pre 0-3个月 日期至167-8月左右\",\"salePrice\":15500,\"shopId\":123,\"shopName\":\"云猴全球购\"}";

long startJSON =System.currentTimeMillis();

JSONObject obj = null;

for (int i = 0; i < LOOP_COUNT; i++){

obj =JSONObject.parseObject(jsonStr);

}

System.out.println("JSON : "+ (System.currentTimeMillis() - startJSON)+"ms");

}

private static byte[]buildFlatBuffersByte() {

FlatBufferBuilder fbb = newFlatBufferBuilder(1);

int productBnOS =fbb.createString("MG120394938912345");

int productNameOS =fbb.createString("德国爱他美Aptamil Pre 0-3个月 日期至167-8月左右");

int shopNameOS =fbb.createString("云猴全球购");

int imgUrlOS =fbb.createString("http://img2.bbgstatic.com/14e2a07cbd5_2_8f02bdb34427ec107124fd1576287310_800x800.jpeg");

//注意,创建字符串(createString)要在XXX.startXXX方法执行之前,否则会出现异常

Product.startProduct(fbb);

Product.addProductId(fbb, 123456l);

Product.addShopId(fbb, 123);

Product.addProductBn(fbb, productBnOS);

Product.addProductName(fbb,productNameOS);

Product.addShopName(fbb, shopNameOS);

Product.addImgUrl(fbb, imgUrlOS);

Product.addCostPrice(fbb, 15000l);

Product.addSalePrice(fbb, 15500l);

Product.addMarketable(fbb, true);

int endOffset =Product.endProduct(fbb);

Product.finishProductBuffer(fbb,endOffset);

byte[] originalData =fbb.dataBuffer().array();

byte[] dataByte =Arrays.copyOfRange(originalData, fbb.dataBuffer().position(),(fbb.dataBuffer().position() +fbb.offset()));

return dataByte;

}

}

结果是,还是有点差距的:

执行5000000次解析耗时比较

FlatBuffers : 98ms

JSON : 10375ms

http://blog.csdn.net/u010019717



替代Protocol buffers 的FlatBuffers:高效利用内存的序列化函数库(Unity中测试)相关推荐

  1. 一个完整利用InternetOpen等系列函数进行下载的测试例子

    2011-08-14 12:03 一个完整利用InternetOpen等系列函数进行下载的测试例子 // TODO: Add extra validation here  HINTERNET hsse ...

  2. 【STM32】利用 C 语言 strchar() 函数查找字符串中指定字符的位置

    文章目录 字符串中查找字符 strchr() 描述 声明 参数 返回值 字符串分割 strtok() 描述 声明 参数 返回值 自己的函数 字符串中查找字符 strchr() 描述 C 库函数 cha ...

  3. 利用python的强大函数库,实现波形的小波降噪、带通滤波、时阈分析、FFT波形转换

    import math import matplotlib.pyplot as plt import pywt import pandas as pd import numpy as np impor ...

  4. Protocol Buffers的应用

    1. Protocol Buffers的介绍 Protocol buffers are Google's language-neutral, platform-neutral, extensible ...

  5. ceaspectusS成熟船公司航运人工智能随时随地验箱上报箱况+箱轨迹报备,实现集装箱套箱云堆场,精细化箱管控+好箱高效利用

    上海人工智能领军企业ceaspectusS™成熟船公司航运人工智能,随时随地验箱上报箱况+箱轨迹报备,实现套箱/云堆场,提升船公司精细化智能化箱管控+好箱利用率. 通过CIMCAI全球领先的成熟航运人 ...

  6. ios开发中计算代码运算时间_理解Unity中的优化(二):内存

    内存: 内存消耗是一个关键的性能指标,尤其是在内存资源有限的平台上,比如低端移动设备. 内存消耗分析: 在Unity中诊断内存问题,Unity介绍了一款开元的可视化内存分析工具--MemoryProf ...

  7. FlatBuffers vs Protocol Buffers

    FlatBuffers去年发布,最近看了一下,与同是出自Google之手的Protocol Buffers非常类似.在官网上介绍,FlatBuffers(简称FB)主要针对game developme ...

  8. JSON与Protocol Buffers的一些比较

    转载来源:http://www.cnblogs.com/zhubo/archive/2011/07/06/JSON_And_ProtocolBuffers.html JSON与Protocol Buf ...

  9. C++程序员Protocol Buffers基础指南

    这篇教程提供了一个面向 C++ 程序员关于 protocol buffers 的基础介绍.通过创建一个简单的示例应用程序,它将向我们展示: 在 .proto 文件中定义消息格式 使用 protocol ...

最新文章

  1. dropbear编译安装及服务脚本编写
  2. 由粗到精学习LVI-SAM:论文原文解析
  3. 5分钟教你写出一份完美的PRD文档(附案例)
  4. 基于android的条码识别技术,基于Android手机的条码识别系统研究
  5. 我的Python成长之路---第六天---Python基础(19)---2016年2月20日(晴)
  6. java中dynamic_java中dynamic web project与web project 的区别 [转]
  7. Azure Linux VM密钥登录
  8. Axure 9 案例教程基础篇之课程简介(助你快速进入实战阶段)
  9. 锐起3.1无盘服务器,[迎新春]锐起3.1无盘XP万能包13V2(IE8版本)
  10. 51单片机SG90舵机控制原理
  11. 经纬度十进制与度分秒换算及数据库实现
  12. SDCC 2017·深圳站八大不容错过的理由
  13. Angular导出功能(excel导出功能、文件数据流导出功能、图片的下载导出功能)
  14. 所生成项目的处理器架构“MSIL”与引用“***”的处理器架构“x86”不匹配。这种不匹配可能会导致运行时失败。请考虑通过配置管理器更改您的项目的目标处理器架构,以使您的项目与引用间的处理器架构...
  15. Bootstrap 徽章
  16. antv/G6自定义边
  17. 动态图表交互揭秘:制作选择器的奥秘
  18. 透彻理解css的grid布局
  19. 付款条件Payment Terms
  20. 软件测试失业了如何再就业

热门文章

  1. java计算机毕业设计精准扶贫管理系统源程序+mysql+系统+lw文档+远程调试
  2. upupw 5.4配置的php,《Zendstudio12+UPUPW+PHP5.4开发平台配置过程》,upupwzendguard_PHP教程...
  3. linux centos 7查看网卡信息,CentOS 7系统中查看网卡信息
  4. React boil
  5. python程序设计请计算从公元1年1月_使用Python计算今天距离公元1年1月1日的天数...
  6. 广告点阵屏和熟悉字模软件的使用
  7. 开店创业缺什么都不能缺水獭掌柜,外卖接单有它太省心
  8. 项目实训记录(1-2周)
  9. 微信小程序直播消耗服务器流量,微信小程序直播强大流量的背后
  10. 还在为投稿发愁吗?ICCVIT 2023,一个计算机、视觉与智能技术国际会议