Protobuf的简易介绍、使用以及分析

  ES6 Generators系列:

  1. ES6
    Generators基本概念
  2. 深入研讨ES6 Generators
  3. ES6
    Generators的异步应用
  4. ES6 Generators并发

  如果您早就读了之系列的眼前三篇稿子,那么您一定对ES6
generators非常了解了。希望你可知从中有所得并被generator发挥其实在的来意。最后咱们只要探讨的这个主题可能会见让您血脉喷张,让您绞尽脑汁(说实话,写就首文章为自己那个费脑子)。花点时间看下文章被的这些事例,相信对君要不行有帮的。在学习上的投资会叫您将来受益无穷。我了相信,在未来,JS中那些复杂的异步能力将起源于我这里的有些想法。

 

 

 

CSP(Communicating Sequential Processes)

  首先,我勾勒这同名目繁多文章完全是为Nolen
@swannodette精美工作的启发。说确实,他形容的有着文章还值得去念一朗诵。我这里发生部分链接可以享用给您:

  • Communicating Sequential
    Processes
  • ES6 Generators Deliver Go Style
    Concurrency
  • Extracting
    Processes

  好了,让咱专业开对是主题的探究。我非是一个由所有Clojure(Clojure凡是如出一辙种运行于Java平台及的
Lisp
方言)背景转投到JS阵营的程序员,而且我为不曾任何Go或者ClojureScript的经验。我发现自己在念这些章的下快便见面失掉兴趣,因此我只能开过多底实验并从中了解及部分卓有成效之物。

  于这历程遭到,我以为自身都出了有一样之考虑,并追一致的对象,而这些还源自于一个请勿那么死板的想方法。

  我尝试创建了一个再次简约的Go风格的CSP(以及ClojureScript
core.async)APIs,同时自己期待能够保留大部分之脚功能。也许有大神会看到自己文章被落之地方,这统统产生或。如果算这样的话,我想我的追能够取得更为的上进与演化,而我啊将跟豪门齐声来享受者历程!

 

Protobuf的简介绍、使用以及剖析

 

详解CSP原理(一点点)

  到底什么是CSP?说其是”communicating”,”Sequential”,”processes”到底是啊意思吧?

  首先,CSP一词源自于Tony Hoare所著的“Communicating Sequential
Processes”一写。里面全是有关CS的辩解,如果您对学术方面的物感兴趣的话,这本开纯属值得一念。我毫不打算盖同样栽被人口为难明白的,深奥的,计算机是的措施来论述这个主题,而是会因同栽轻松的脱产的方法来进行。

  那咱们虽从”Sequential”开始吧!这有君该就挺熟悉了。这是另外一种植谈论有关单线程和ES6
generators异步风格代码的措施。我们来回顾一下generators的语法:

function *main() {
    var x = yield 1;
    var y = yield x;
    var z = yield (y * 2);
}

  上面代码中之各一样条告句都见面按梯次一个一个地履。Yield根本字标明了代码中让封堵的触发(只能于generator函数自己死,外部代码不可知围堵generator函数的履行),但是非会见改*main()函数中代码的实践顺序。这段代码很粗略!

  接下我们来讨论一下”processes”。这个是什么啊?

  基本上,generator函数有点像一个虚拟的”process”,它是我们先后的一个单身的有的,如果JavaScript允许,它完全可以与程序的另一些并行执行。这听起似乎产生三三两两荒唐!如果generator函数访问共享内存(即,如果它们访问除了自己中定义之部分变量之外的“自由变量”),那么它们就不是一个独门的局部。现在我们借设有一个未聘外部变量的generator函数(在FP(Functional
Programming函数式编程)的辩护被我们拿它们称作一个”combinator”),因此从理论及吧她好当融洽的process中运作,或者说作为协调的process来运作。

  但是我们说的是”processes”,注意这个单词用的是复数,这是坐见面是个别个或多单process在同一时间运行。换句话说,两独或多独generators函数会为安放一起来协同工作,通常是为完成同样桩于充分的任务。

  为什么要为此多个单身的generator函数,而无是将她都放到一个generator函数里吗?一个无比要之原由就是是:功用跟关注点的分手。对于一个职责XYZ来说,如果您将它们说明成子任务X,Y和Z,那么以每个子任务协调的generator函数中来贯彻效益将见面使代码更易理解与保障。这与拿函数XYZ()拆分成X()Y(),和Z(),然后在X()中调用Y(),在Y()中调用Z()大凡平的道理。我们将函数分解成一个个单身的子函数,降低代码的耦合度,从而使程序更为爱保障。

一、protobuf是什么?

        protobuf(Google Protocol
Buffers)是Google提供一个具备高效之说道数据交换格式工具库(类似Json),但相比之下于Json,Protobuf有重新胜似之转账效率,时间效率和空中效率都是JSON的3-5加倍。后面将会晤起略的demo对于当下片种格式的数目转发效率的对比。但以此库房时采取还非是最好盛,据说谷歌内部多活都产生采取。

 

对多只generators函数来说我们吧堪成功这或多或少

  这就要说及”communicating”了。这个以是什么啊?就是协作。如果我们将多单generators函数放在有协同工作,它们彼此之间需要一个通信信道(不仅仅是访问共享的作用域,而是一个着实的足于她访问的独占式共享通信信道)。这个通信信道是呀吧?不管而发送什么内容(数字,字符串等),事实上你都未需要通过信道发送信息来展开通信。通信会像合作那样简单,就比如以顺序的控制权从一个地方转移到另外一个地方。

  为什么要更换控制?这关键是因JS是单线程的,意思是说以自由给定的一个日子有外只有见面起一个程序于运行,而别程序还处在暂停状态。也就是说其它程序还远在它们各自职责之中间状态,不过仅仅是被中止实施,必要常常会东山再起并蝉联运行。

  任意独立的”processes”之间可以神奇地拓展通信与合作,这听起有些不因谱。这种解耦的想法是好的,但是有接触未切实际。相反,似乎其他一个成功之CSP的落实还是对那些问题领域被已在的、众所周知的逻辑集的特有说,其中每个片都受突出设计过因此让每组成部分内都能够好好工作。

  或许我之知情了是拂的,但是自己还从来不见到其他一个具体的计,能够被有限独随机给定的generator函数可以坐某种方式自由地聚集合在一起形成CSP对。它们都需吃设计成会及外一些共干活,需要按彼此间的通信协议等等。

 

二、protobuf有什么?

        Protobuf
提供了C++、java、python语言的支撑,提供了windows(proto.exe)和linux平台动态编译生成proto文件对应的源文件。proto文件定义了商讨数被之实业结构(message
,field)

关键字message: 代表了实体结构,由多单消息字段(field)组成。

信字段(field): 包括数据类型、字段名、字段规则、字段唯一标识、默认值

数据类型:常见的原子类型且支持(在FieldDescriptor::kTypeToName中发生定义)

字段规则:(在FieldDescriptor::kLabelToName中定义)

        required:必须初始化字段,如果无赋值,在数码序列化时见面扔来十分

        optional:可卜字段,可以无需初始化。

        repeated:数据可以重新(相当于java 中之Array或List)

        字段唯一标识:序列化和倒序列化将会晤采取到。

默认值:在概念信息配段时方可为出默认值。

 

JS中的CSP

  于将CSP的论战以及JS中,有一部分老大有趣之追究。前面提到的David
Nolen,他出几乎独坏有意思之种,包括Om,以及core.async。Koa仓库(node.js)主要通过它的use(..)措施体现了当下一点。而除此以外一个针对性core.async/Go
CSP API十分忠诚的仓库是js-csp。

  你真的应该去探望这些伟大之类型,看看里面的各种法子和例子,了解它是哪在JS中实现CSP的。

 

老三、protobuf有什么用?

       
Xml、Json是当前常用之数据交换格式,它们一直用字段名称保护序列化后类实例中字段与数量里的炫耀关系,一般用字符串的形式保留在序列化后的字节流中。消息及信息之概念相对独立,可读性较好。但序列化后底数字节很可怜,序列化和反序列化的岁月比较丰富,数据传效率不高。

       
Protobuf和Xml、Json序列化的方法各异,采用了第二向前制字节的序列化方式,用配段索引同字段类型通过算法计算得到字段之前的涉及映射,从而达到更胜之日子效率以及空间效率,特别符合对数码大小和传输速率比较灵活的场地用。

异步的runner(..):设计CSP

  因为自一直以全力以赴探索以互相的CSP模式应用至我好之JS代码中,所以于利用CSP来扩张自己自己之异步流程控制库asynquence来说就是是平等项顺理成章的转业。我勾勒过的runner(..)插件(看上一首稿子:ES6
Generators的异步应用)就是之所以来拍卖generators函数的异步运行的,我意识它们可充分轻受扩张用来拍卖多generators函数在同一时间运行,就是如CSP的方那样。

  我一旦解决之首先单规划问题是:如何才能够清楚哪位generator函数将得到下一个控制权?

  要化解各个generators函数之间的信还是控制权的传递,每个generator函数都不能不有一个能够被另外generators函数知道的ID,这看起像过于笨拙。经过各种尝试,我设定了一个简易的巡回调度方式。如果你配合了三单generators函数A,B和C,那么A将优先抱控制权,当A
yield时B将接管A的控制权,然后当B yield时C将接管B,然后以是A,以此类推。

  但是如何才会实际转移generator函数的控制权也?应该出一个显式的API吗?我再也开展了各种尝试,然后设定了一个越来越隐式的点子,看起和Koa有硌类似(完全是外面):每个generator函数都得一个共享”token”的援,当yield时即便代表若将控制权进行转移。

  另一个题材是信通道应该加上什么。一种是非常专业的通信API如core.async和js-csp(put(..)take(..))。但是当我透过各种尝试后,我于支持于任何一样种不顶正统的法子(甚至都称不上API,而单独是一个共享的数据结构,例如数组),它看起像是比靠谱的。

  我主宰利用数组(称之为消息),你得因需要控制哪些填写和清空数组的内容。你可以push()信息及数组中,从数组中pop()消息,按照约定以不同的信存放到数组中一定的职务,并于这些职务存放更复杂的数据结构等。

  我之困惑是来头任务要传递简单的信,而聊则用传递复杂的音,因此不用在部分简单的景况下强制这种复杂度,我选不拘泥于信息通道的款式要采用数组(除数组自我他这里没有任何API)。在一些情况下她杀爱在附加的款式上对消息传递机制进行分,这对准咱们来说挺有因此(参见下的状态机示例)。

  最终,我意识这些generator
“processes”仍然得益于那些单身的generators可以应用的异步功能。也就是说,如果无yield控制token,而yield一个Promise(或者一个异步队列),则runner(..)的确会暂停为等待返回值,但是切莫见面更换控制权,它见面以结果返回给当下的process(generator)而保留控制权。

  最后一点或者是最有争议或同本文中任何库差别最老的(如果我讲是的说话)。也许的确的CSP对这些方式不屑一顾,但是本人意识自家之挑选还是十分有因此的。

 

季、Protobuf在Android上之使

1、创建proto文件,定义消息之实业结构

2、编译proto文件生成对应之java文件

3、添加protobuf-java-2.5.0.jar到android工程

4、在android中实现对信息结构的序列化/反序列化  

 

一个傻乎乎的FooBar示例

  好了,理论的物摆得差不多了。我们来看看具体的代码:

// 注意:为了简洁,省略了虚构的`multBy20(..)`和`addTo2(..)`异步数学函数

function *foo(token) {
    // 从通道的顶部获取消息
    var value = token.messages.pop(); // 2

    // 将另一个消息存入通道
    // `multBy20(..)`是一个promise-generating函数,它会延迟返回给定值乘以`20`的计算结果
    token.messages.push( yield multBy20( value ) );

    // 转移控制权
    yield token;

    // 从CSP运行中的最后的消息
    yield "meaning of life: " + token.messages[0];
}

function *bar(token) {
    // 从通道的顶部获取消息
    var value = token.messages.pop(); // 40

    // 将另一个消息存入通道
    // `addTo2(..)` 是一个promise-generating函数,它会延迟返回给定值加上`2`的计算结果
    token.messages.push( yield addTo2( value ) );

    // 转移控制权
    yield token;
}

  上面的代码中来零星个generator
“processes”,*foo()*bar()。它们还收到并处理一个令牌(当然,如果你肯你可随意给什么都实施)。令牌上的性质messages即使是咱们的共享信息通道,当CSP运行时它们见面赢得初始化传入的消息值进行填写(后面会摆到)。

  yield
token
显式地拿控制权转移至“下一个”generator函数(循环顺序)。但是,yield
multBy20(value)
yield
addTo2(value)
犹是yield一个promises(从这半个虚构的延计算函数中归的),这象征generator函数此时凡地处中断状态直到promise完成。一旦promise完成,当前处在控制着之generator函数会恢复并继承运行。

  无论最终yield会见回去什么,上面的事例中yield返回的是一个表达式,都表示我们的CSP运行成功的信(见下文)。

  现在我们出点儿单CSP process
generators,我们来看望哪运行它们?使用asynquence:

// 开始一个sequence,初始message的值是2
ASQ( 2 )

// 将两个CSP processes进行配对一起运行
.runner(
    foo,
    bar
)

// 无论接收到的message是什么,都将它传入sequence中的下一步
.val( function(msg){
    console.log( msg ); // 最终返回42
} );

  这单是一个良简短的例子,但我觉着它们能很好地用来说明上面的这些概念。你得品尝一下(试着转部分价值),这有助于你懂这些概念并团结下手编写代码!

 

五、Protobuf与json的对比

其余一个事例Toy Demo

  让咱们来拘禁一个经的CSP例子,但只是于咱当下已有些有些简便的发现开始,而不是起咱一般所说的纯粹学术的角度来展开讨论。

  Ping-pong。一个老大有意思的戏,对也?也是本身最欣赏的倒。

  让我们来设想一下您既完结了是乒乓球游戏的代码,你通过一个循环来运转游戏,然后起有限局部代码(例如在ifswitch语词被的分段),每一样组成部分代表一个遥相呼应的玩家。代码运行正常,你的打运行起来就是比如是一个乒乓球冠军!

  但是仍我们地方讨论过的,CSP在这里从及了哪的图吗?尽管是成效与关注点的分开。那么具体到我们的乒乓球游戏中,这个分离指的虽是星星独不同的玩家

  那么,我们好以一个要命强之框框达到之所以单薄单”processes”(generators)来拟我们的玩耍,每个玩家一个”process”。当我们贯彻代码细节之早晚,我们会发现于少数单玩家的拙存在操纵的切换,我们叫”glue
code”(胶水代码(译:在微机编程领域,胶水代码也吃粘合代码,用途是贴边那些或不般配的代码。可以应用与胶合在一起的代码相同之语言编写,也足以为此单独的胶水语言编写。胶水代码不实现程序要求的其余功效,它通常出现于代码中,使现有的库房或者程序在外部函数接口(如Java本地接口)中开展互操作。胶水代码在速原型开发环境被深快,可以被几乎只零部件为快速集成到么语言或框架中。)),这个任务自我也许需要第三单generator的代码,我们得以用她套成游戏的裁判

  我们打算过了各种特定领域的问题,如计分、游戏机制、物理原理、游戏策略、人工智能、操作控制等。这里我们唯一用关爱的有的就是是模仿打台球的往返过程(这事实上为意味了俺们CSP的决定转移)。

  想看demo的讲话可于这里运转(注意:在支撑ES6
JavaScript的时髦版本的FireFox
nightly或Chrome中查看generators是何许行事之)。现在,让我们一同来探望代码。首先,来看望asynquence
sequence长什么样?

ASQ(
    ["ping","pong"], // 玩家姓名
    { hits: 0 } // 球
)
.runner(
    referee,
    player,
    player
)
.val( function(msg){
    message( "referee", msg );

  我们初始化了一个messages sequence:[“ping”, “pong”]{hits:
0}
。一会儿晤为此到。然后,我们装了一个含有3个processes运行的CSP(相互协同工作):一个*referee()和两个*player()实例。在娱乐结束时最后之message会被传送给sequence中的生一样步,作为referee的出口message。下面是referee的兑现代码:

function *referee(table){
    var alarm = false;

    // referee通过秒表(10秒)为游戏设置了一个计时器
    setTimeout( function(){ alarm = true; }, 10000 );

    // 当计时器警报响起时游戏停止
    while (!alarm) {
        // 玩家继续游戏
        yield table;
    }

    // 通知玩家游戏已结束
    table.messages[2] = "CLOSED";

    // 裁判宣布时间到了
    yield "Time's up!";
}
} );

  这里我们为此table来学控制令牌以解决我们地方说的那些特定领域的问题,这样就是可知生好地来叙述当一个玩家用球打回去的上控制权被yield给另外一个玩家。*referee()中的while巡回代表要秒表没有停歇,程序即使会见直接yield
table
(将控制权转移给另外一个玩家)。当计时器结束时离while循环,referee将会晤接管控制权并发表”Time’s
up!
“游戏了了。

  再来探*player() generator的贯彻代码(我们利用简单个实例):

function *player(table) {
    var name = table.messages[0].shift();
    var ball = table.messages[1];

    while (table.messages[2] !== "CLOSED") {
        // 击球
        ball.hits++;
        message( name, ball.hits );

        // 模拟将球打回给另一个玩家中间的延迟
        yield ASQ.after( 500 );

        // 游戏继续?
        if (table.messages[2] !== "CLOSED") {
            // 球现在回到另一个玩家那里
            yield table;
        }
    }

    message( name, "Game over!" );
}

  第一只玩家将他的名起message数组的第一独元素中移除(”ping“),然后第二单玩家获得他的讳(”pong“),以便他们还能够科学地辨别自己(译:注意这里是少单*player()的实例,在有限独不等的实例中,通过table.messages[0].shift()足拿走各自不同的玩家名字)。同时片只玩家都维持对共享球的引用(使用hits计数器)。

  当玩家还无听到判决说罢,就“击球”并累加计数器(并出口一个message来通知其),然后等待500毫秒(假设球盖光速运行不占其他时刻)。如果游戏还当继承,他们即yield
table到其他一个玩家那里。就是这般。

  在这里好查阅完代码,从而了解代码的各片是怎么样行事的。

 

1、创建product.proto文件

        定义了三单Message(ProductInfo、PhoneInfo、Watch)消息结构

图片 1

状态机:Generator协同程序

  最后一个例子:将一个状态机概念为由一个大概的helper驱动的一致组generator协同程序。Demo(注意:在支持ES6
JavaScript的最新版本的FireFox
nightly或Chrome中翻generators是怎样工作的)。

  首先,我们定义一个helper来控制有限的状态处理程序。

function state(val,handler) {
    // 管理状态的协同处理程序(包装器)
    return function*(token) {
        // 状态转换处理程序
        function transition(to) {
            token.messages[0] = to;
        }

        // 默认初始状态(如果还没有设置)
        if (token.messages.length < 1) {
            token.messages[0] = val;
        }

        // 继续运行直到最终的状态为true
        while (token.messages[0] !== false) {
            // 判断当前状态是否和处理程序匹配
            if (token.messages[0] === val) {
                // 委托给状态处理程序
                yield *handler( transition );
            }

            // 将控制权转移给另一个状态处理程序
            if (token.messages[0] !== false) {
                yield token;
            }
        }
    };
}

  state(..)
helper也一定的状态值创造了一个delegating-generator包装器,这个包器会自动运行状态机,并当每个状态切换时移控制权。

  依照惯例,我操运用共享token.messages[0]的位置来保存我们状态机的此时此刻状态。这象征你可透过由序列中前一模一样步传的message来设定初始状态。但是一旦没有传到初始值的讲话,我们会略地用第一独状态作为默认的初始值。同样,依照惯例,最终之状态会被如为false。这十分易改为合你协调的急需。

  状态值可以是另外你想如果的价值:numbersstrings对等。只要该值可以被===运算符严格测试通过,你尽管足以采用它们作为你的状态。

  以下面的言传身教中,我显得了一个状态机,它好按照一定的逐一以四单数值状态里进行转换:1->4->3->2。为了演示,这里以了一个计数器,因此可以实现多次循环转换。当我们的generator状态机到达最终状态时(false),asynquence序列就见面像你所期的那样走至下一致步。

// 计数器(仅用作演示)
var counter = 0;

ASQ( /* 可选:初始状态值 */ )

// 运行状态机,转换顺序:1 -> 4 -> 3 -> 2
.runner(

    // 状态`1`处理程序
    state( 1, function*(transition){
        console.log( "in state 1" );
        yield ASQ.after( 1000 ); // 暂停1s
        yield transition( 4 ); // 跳到状态`4`
    } ),

    // 状态`2`处理程序
    state( 2, function*(transition){
        console.log( "in state 2" );
        yield ASQ.after( 1000 ); // 暂停1s

        // 仅用作演示,在状态循环中保持运行
        if (++counter < 2) {
            yield transition( 1 ); // 跳转到状态`1`
        }
        // 全部完成!
        else {
            yield "That's all folks!";
            yield transition( false ); // 跳转到最终状态
        }
    } ),

    // 状态`3`处理程序
    state( 3, function*(transition){
        console.log( "in state 3" );
        yield ASQ.after( 1000 ); // 暂停1s
        yield transition( 2 ); // 跳转到状态`2`
    } ),

    // 状态`4`处理程序
    state( 4, function*(transition){
        console.log( "in state 4" );
        yield ASQ.after( 1000 ); // 暂停1s
        yield transition( 3 ); // 跳转到状态`3`
    } )

)

// 状态机完成,移动到下一步
.val(function(msg){
    console.log( msg );
});

  应该非常爱地钉点的代码来查看究竟出了什么。yield
ASQ.after(1000)
著了这些generators可以依据需要做任何项目的依据promise/sequence的异步工作,就比如我们在头里所观看底同一。yield
transition(…)
意味着什么更换到一个初的状态。上面代码中的state(..)
helper完成了处理yield*
delegation同状态转换的关键办事,然后所有程序的关键流程看起很简练,表述也格外清晰流利。

 

2、消息结构对应之java类(ProductInfo、PhoneInfo、Watch)

图片 2

 

总结

  CSP的重要是用鲜独或重多的generator
“processes”连接于同步,给它们一个共享的通信信道,以及同栽好于竞相间传输控制的方法。

  JS中发生诸多的库都或多还是有失地采取了一定专业的法门来跟Go和Clojure/ClojureScript
APIs或语义相匹配。这些库的默默都富有好高的开发者,对于更为探讨CSP来说他们还是深好之资源。

  asynquence计算下同一栽不绝规范而同时欲还能够保留重要组织的不二法门。如果没有别的
,asynquence的runner(..)足作为你试和学CSP-like
generators的入门。

  最好的一对是asynquence
CSP与外异步功能(promises,generators,流程控制相当)在一块儿干活。如此一来,你虽得以掌控一切,使用另外你手头上适当的家伙来好任务,而富有的当下整个还止当一个细微的lib中。

  现在咱们就当这四首文章被详尽探索了generators,我想而能够从中受益并取得灵感以探讨如何改造自己之异步JS代码!你拿用generators来创造什么吧?

 

初稿地址:https://davidwalsh.name/es6-generators

3、消息结构和java对象赋值

PhoneName:” idol3”

Price:2000

Top:1

 

WatchName:” tcl watch”

Price:1000

Top:1

 

4、JSON字符串

 

{“phone”:{“phoneName”:”idol3″,”price”:2000,”top”:1},”watch”:{“watchName”:”tcl
wtch”,”top”:1,”price”:1000}}

 

5、Protobuf转化后底二进制文件

图片 3

 

空中效率

Json:107个字节

Protobuf:32个字节

 

日子效率

Json序列化: 1ms ,  反序列化:0ms

Protobuf 序列化: 0ms 反序列化:0ms

 

以public List<Phone> list和repeated PhoneInfo phoneInfoList
=3;都赋值为1000独PhoneInfo

 

空中效率

Json:4206个字节

Protobuf:1332个字节

 

日效率

Json序列化: 4ms ,  反序列化:1ms

Protobuf 序列化: 1ms 反序列化:0ms

六、protobuf的简单解析

1、优缺点

亮点:通过上述之时间效率以及空中效率,可以看到protobuf的空间效率是JSON的2-5倍,时间效率要高,对于数据大小敏感,传输效率高之模块可以protobuf库

 

缺陷:消息结构可读性不愈,序列化后的字节序列为二进制序列不可知简单的分析中;目前使用非普遍,只支持java,C++和Python;

 

2、数据序列化/反序列化

a、规则:

protobuf把信结果message也是通过
key-value对来表示。只是内的key是运用一定之算法计算出来的就是通过每个message中每个字段(field
index)和字段的数据类型进行演算得来的key = (index<<3)|type;

type类型的附和关系如下:

 

Type

Meaning

Used For

0

Varint

int32, int64, uint32, uint64, sint32, sint64, bool, enum

1

64-bit

fixed64, sfixed64, double

2

Length-delimited

string, bytes, embedded messages, packed repeated fields

3

Start group

groups (deprecated)

4

End group

groups (deprecated)

5

32-bit

fixed32, sfixed32, float

 

Value会根据数据类型的不等会发出个别种表现形式:

于各种int,bool,enum类型,value就是Varint

对于string,bytes,message等等类型,value就是length+原始内容编码

 

Varints是千篇一律种植艰苦凑表示数字的法子。它之所以一个还是基本上个字节表示一个数字,值更小的数字字节数更是少。相对于传统的用4字节意味着int32项目数字,Varints对于小于128的数值都得就此一个字节表示,大于128之数值会用重新多之字节来代表,对于大酷的数目虽然用用5个字节来代表。

 

Varints算法描述:
每一个字节的最高位都是有非常含义的,如果是1,则意味继续之字节也是该数字之相同有的;如果是0,则结束

b、demo生成的的二进制文件反序列化。

第1个字节 (0A)

字段索引(index):         0A = 0001010  0A>>3 = 001 = 1

数据类型(type):           0A = 0001010&111  = 2 (String);

 

第2个字节 (0C)

字符串长度(length):      0E = 12;

字符串:                         0A 05 69 64 6F 6C 33 10 01 18 BD 0F

 

第3个字节 (0A)

坐字符串是出自phoneInfo属于嵌套类型

许段索引(index):         0A = 0001010  0A>>3 = 001 = 1

数据类型(type):           0A = 0001010&111  = 2 (String);

第4-9个字节(69 64 6F 6C 33)

字符串长度(length):    05 = 5

字符串:                       69 64 6F 6C 33 = idol3

 

第10个字节 (10)

许段索引(index):         10 = 00010000    10A>>3 = 0010 = 2

数据类型(type):           10 = 00010000&111  = 0 (Varints);

 

第11个字节  (01)

Varints:                          01 = 00001字节的高位呢0 整数结束

Value:                            1;

 

第12个字节(18)

字段索引(index):           18 = 00011000    18>> 00011 = 3

数据类型(type):           18 = 00011000&111  = 0 (Varints);

 

第13个字节(D0)

高位也1,整数计算到下一个字节

 

第14个字节(0F)

参天位吗0,整数计算了

Value:为11111010000 =2000

 

C、反序列化结果

phoneinfo为

phoneName = “idol3”

top = 1

price = 2000;

 

同样的主意watchInfo为:

watchName = “tcl name”

top = 1

price=2000 

3、时间效率

经protobuf序列化/反序列化的历程可得出:protobuf是由此算法生成二上制流,序列化与反序列化不需要分析相应的节点性与剩下的叙说信息,所以序列化和反序列化时间效率比较高。

4、空间效率

xml、json是用字段名称来规定类实例中字段之间的独立性,所以序列化后的数量多了多叙述信息,增加了序列化后底字节序列的容量。

 

Protobuf的序列化/反序列化过程可以汲取:

protobuf是由于字段索引(fieldIndex)与数据类型(type)计算(fieldIndex<<3|type)得出的key维护字段之间的照射且只占一个字节,所以相比json与xml文件,protobuf的序列化字节没有过多之key与叙称信息,所以占用空间要多少多。

七、Protobuf的源码分析

1、protobuf在java使用的序列化流程

 

java程序调用parserFrom(byte[]
data)开始字节序列的反倒序列,Java程序通过调用编译生类GenerateMessage中之wirteTo()方法开始将序列化后底字节写副输出流中

 图片 4

图片 5

GenerateMessage
继承AbstractMessage类,序列化最终于AbstractMesssage中就,序列化的贯彻过程:

a、遍历对象中Message结构()

调用AbstractMessage类中的writeTo()方法

 图片 6

b、 序列化Message中各一个字段

调用CodeOutputStream类中的writeMessageSetExtension()方法

图片 7

 

c、 对于Varints  Tag 的序列化流程:

调用CodeOutputStream类中的writeUInt32()方法

图片 8

调用CodeOutputStream类中的WriteRawVarint32()方法

图片 9

 

d、 对于非Varints Tag的序列化

调用CodeOutputStream类中的WriteTag()方法

图片 10 

图片 11

 

现实的序列化实现还在CodedOutputStream中成功

 

2、java以protobuf 的反序列化流程分析

java程序通过调用parserFrom(byte[] data)开始反序列化

 图片 12

图片 13

实际以com.google.protobuf. AbstractParser类中实现

 

图片 14

 

图片 15

图片 16

 

图片 17

 

 

末了当com.google.protobuf.CodedInputStream类中形成反序列化

3、动态编译

因为windows下用protoc.exe工具实现proto文件编译为例,protoc.exe是故C++实现。在控制台执行命令:

图片 18

编译的流程:

检查proto的语法规则

用proto的文书中之message结构转换为GenerateMessage类的子类,并促成Builder接口。

编译流程

Main.cc中的main()方法

图片 19

 

Command_line_interface.cc中的Run()方法

图片 20

 

Import类中Import()

图片 21

 

当Descriptor中做到message消息的募集和转发。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图