github.com/cloudwego/frugal@v0.1.15/README.md (about)

     1  # Frugal
     2  
     3  English | [中文](README_cn.md)
     4  
     5  A very fast dynamic Thrift serializer & deserializer based on just-in-time compilation.
     6  
     7  ## Features
     8  
     9  ### Code Generation Free
    10  
    11  Traditional Thrift serializer and deserializer are based on generated code which is no longer needed since we can use JIT compilation to dynamically generate machine code.
    12  
    13  ### High Performance
    14  
    15  Thanks to JIT compilation, Frugal can generate better machine code than Go language compiler. In multi-core scenarios, Frugal's performance is about 5 times higher than that of traditional serializer and deserializer.
    16  
    17  ```text
    18  name                                 old time/op    new time/op     delta
    19  MarshalAllSize_Parallel/small-16       78.8ns ± 0%     14.9ns ± 0%    -81.10%
    20  MarshalAllSize_Parallel/medium-16      1.34µs ± 0%     0.32µs ± 0%    -76.32%
    21  MarshalAllSize_Parallel/large-16       37.7µs ± 0%      9.4µs ± 0%    -75.02%
    22  UnmarshalAllSize_Parallel/small-16      368ns ± 0%       30ns ± 0%    -91.90%
    23  UnmarshalAllSize_Parallel/medium-16    11.9µs ± 0%      0.8µs ± 0%    -92.98%
    24  UnmarshalAllSize_Parallel/large-16      233µs ± 0%       21µs ± 0%    -90.99%
    25  
    26  name                                 old speed      new speed       delta
    27  MarshalAllSize_Parallel/small-16     7.31GB/s ± 0%  38.65GB/s ± 0%   +428.84%
    28  MarshalAllSize_Parallel/medium-16    12.9GB/s ± 0%   54.7GB/s ± 0%   +322.10%
    29  MarshalAllSize_Parallel/large-16     11.7GB/s ± 0%   46.8GB/s ± 0%   +300.26%
    30  UnmarshalAllSize_Parallel/small-16   1.56GB/s ± 0%  19.31GB/s ± 0%  +1134.41%
    31  UnmarshalAllSize_Parallel/medium-16  1.46GB/s ± 0%  20.80GB/s ± 0%  +1324.55%
    32  UnmarshalAllSize_Parallel/large-16   1.89GB/s ± 0%  20.98GB/s ± 0%  +1009.73%
    33  
    34  name                                 old alloc/op   new alloc/op    delta
    35  MarshalAllSize_Parallel/small-16         112B ± 0%         0B        -100.00%
    36  MarshalAllSize_Parallel/medium-16        112B ± 0%         0B        -100.00%
    37  MarshalAllSize_Parallel/large-16         779B ± 0%        57B ± 0%    -92.68%
    38  UnmarshalAllSize_Parallel/small-16     1.31kB ± 0%     0.10kB ± 0%    -92.76%
    39  UnmarshalAllSize_Parallel/medium-16      448B ± 0%      3022B ± 0%   +574.55%
    40  UnmarshalAllSize_Parallel/large-16     1.13MB ± 0%     0.07MB ± 0%    -93.54%
    41  
    42  name                                 old allocs/op  new allocs/op   delta
    43  MarshalAllSize_Parallel/small-16         1.00 ± 0%       0.00        -100.00%
    44  MarshalAllSize_Parallel/medium-16        1.00 ± 0%       0.00        -100.00%
    45  MarshalAllSize_Parallel/large-16         1.00 ± 0%       0.00        -100.00%
    46  UnmarshalAllSize_Parallel/small-16       6.00 ± 0%       1.00 ± 0%    -83.33%
    47  UnmarshalAllSize_Parallel/medium-16      6.00 ± 0%      30.00 ± 0%   +400.00%
    48  UnmarshalAllSize_Parallel/large-16      4.80k ± 0%      0.76k ± 0%    -84.10%
    49  ```
    50  
    51  ## What can you do with Frugal ?
    52  
    53  ### Use Frugal as [Kitex](https://github.com/cloudwego/kitex) serializer and deserializer
    54  
    55  No more massive serialization and deserialization code, leads to a more tidy project. No more meaningless diff of generated code in code review.
    56  
    57  ### Serialized and Deserialize struct generated by [Thriftgo](https://github.com/cloudwego/thriftgo)
    58  
    59  If you have a Thrift file, and all you need is using Frugal to do serialization and deserialization. You can use thriftgo to generate Go struct, then you can use Frugal.
    60  
    61  ### Serialization and deserialization on a customized Go struct
    62  
    63  If you don't want any Thrift files, and you want serialize or deserialize a customized Go struct. You can add some struct field tag to the Go struct, then you can use Frugal.
    64  
    65  ## Usage
    66  
    67  ### Using with Kitex
    68  
    69  #### 1. Update Kitex to v0.4.2 or higher version
    70  
    71  ```shell
    72  go get github.com/cloudwego/kitex@latest
    73  ```
    74  
    75  #### 2. Generate code with `-thrift frugal_tag` option
    76  
    77  Example:
    78  
    79  ```shell
    80  kitex -thrift frugal_tag -service a.b.c my.thrift
    81  ```
    82  
    83  If you don't need codec code, you can use `-thrift template=slim` option.
    84  
    85  ```shell
    86  kitex -thrift frugal_tag,template=slim -service a.b.c my.thrift
    87  ```
    88  
    89  #### 3. Init clients and servers with `WithPayloadCodec(thrift.NewThriftFrugalCodec())` option
    90  
    91  Client example:
    92  
    93  ```go
    94  package client
    95  
    96  import (
    97      "context"
    98  
    99      "example.com/kitex_test/client/kitex_gen/a/b/c/echo"
   100      "github.com/cloudwego/kitex/client"
   101      "github.com/cloudwego/kitex/pkg/remote/codec/thrift"
   102  )
   103  
   104  func Echo() {
   105      code := thrift.NewThriftCodecWithConfig(thrift.FastRead | thrift.FastWrite | thrift.FrugalRead | thrift.FrugalWrite)
   106      cli := echo.MustNewClient("a.b.c", client.WithPayloadCodec(codec))
   107      ...
   108  }
   109  ```
   110  
   111  Server example:
   112  
   113  ```go
   114  package main
   115  
   116  import (
   117      "log"
   118  
   119      "github.com/cloudwego/kitex/server"
   120      c "example.com/kitex_test/kitex_gen/a/b/c/echo"
   121      "github.com/cloudwego/kitex/pkg/remote/codec/thrift"
   122  )
   123  
   124  func main() {
   125      code := thrift.NewThriftCodecWithConfig(thrift.FastRead | thrift.FastWrite | thrift.FrugalRead | thrift.FrugalWrite)
   126      svr := c.NewServer(new(EchoImpl), server.WithPayloadCodec(code))
   127  
   128      err := svr.Run()
   129      if err != nil {
   130          log.Println(err.Error())
   131      }
   132  }
   133  ```
   134  
   135  ### Using with Thrift IDL
   136  
   137  #### Prepare Thrift file
   138  
   139  We can define a struct in Thrift file like below:
   140  
   141  my.thrift:
   142  
   143  ```thrift
   144  struct MyStruct {
   145      1: string msg
   146      2: i64 code
   147  }
   148  ```
   149  
   150  #### Use Thriftgo to generate code
   151  
   152  Now we have thrift file, we can use Thriftgo with `frugal_tag` option to generate Go code.
   153  
   154  Example:
   155  
   156  ```shell
   157  thriftgo -r -o thrift -g go:frugal_tag,package_prefix=example.com/kitex_test/thrift my.thrift
   158  ```
   159  
   160  If you don't need codec code, you can use `template=slim` option
   161  
   162  ```shell
   163  thriftgo -r -o thrift -g go:frugal_tag,template=slim,package_prefix=example.com/kitex_test/thrift my.thrift
   164  ```
   165  
   166  #### Use Frugal to serialize or deserialize
   167  
   168  Now we can use Frugal to serialize or deserialize the struct defined in thrift file.
   169  
   170  Example:
   171  
   172  ```go
   173  package main
   174  
   175  import (
   176      "github.com/cloudwego/frugal"
   177  
   178      "example.com/kitex_test/thrift"
   179  )
   180  
   181  func main() {
   182      ms := &thrift.MyStruct{
   183          Msg: "my message",
   184          Code: 1024,
   185      }
   186      ...
   187      buf := make([]byte, frugal.EncodedSize(ms))
   188      frugal.EncodeObject(buf, nil, ms)
   189      ...
   190      got := &thrift.MyStruct{}
   191      frugal.DecodeObject(buf, got)
   192      ...
   193  }
   194  ```
   195  
   196  ### Serialization and deserialization on a customized Go struct
   197  
   198  #### Define a Go struct
   199  
   200  We can define a struct like this:
   201  
   202  ```go
   203  type MyStruct struct {
   204      Msg     string
   205      Code    int64
   206      Numbers []int64 
   207  }
   208  ```
   209  
   210  #### Add Frugal tag to struct fields
   211  
   212  Frugal tag is like `frugal:"1,default,string"`, `1` is field ID, `default` is field requiredness, `string` is field type. Field ID and requiredness is always required, but field type is only required for `list`, `set` and `enum`.
   213  
   214  You can add Frugal tag to `MyStruct` like below:
   215  
   216  ```go
   217  type MyStruct struct {
   218      Msg     string  `frugal:"1,default"`
   219      Code    int64   `frugal:"2,default"`
   220      Numbers []int64 `frugal:"3,default,list<i64>"`
   221  }
   222  ```
   223  
   224  All types example:
   225  
   226  ```go
   227  type MyEnum int64
   228  
   229  type Example struct {
   230   MyOptBool         *bool            `frugal:"1,optional"`
   231   MyReqBool         bool             `frugal:"2,required"`
   232   MyOptByte         *int8            `frugal:"3,optional"`
   233   MyReqByte         int8             `frugal:"4,required"`
   234   MyOptI16          *int16           `frugal:"5,optional"`
   235   MyReqI16          int16            `frugal:"6,required"`
   236   MyOptI32          *int32           `frugal:"7,optional"`
   237   MyReqI32          int32            `frugal:"8,required"`
   238   MyOptI64          *int64           `frugal:"9,optional"`
   239   MyReqI64          int64            `frugal:"10,required"`
   240   MyOptString       *string          `frugal:"11,optional"`
   241   MyReqString       string           `frugal:"12,required"`
   242   MyOptBinary       []byte           `frugal:"13,optional"`
   243   MyReqBinary       []byte           `frugal:"14,required"`
   244   MyOptI64Set       []int64          `frugal:"15,optional,set<i64>"`
   245   MyReqI64Set       []int64          `frugal:"16,required,set<i64>"`
   246   MyOptI64List      []int64          `frugal:"17,optional,list<i64>"`
   247   MyReqI64List      []int64          `frugal:"18,required,list<i64>"`
   248   MyOptI64StringMap map[int64]string `frugal:"19,optional"`
   249   MyReqI64StringMap map[int64]string `frugal:"20,required"`
   250   MyOptEnum         *MyEnum          `frugal:"21,optional,i64"`
   251   MyReqEnum         *MyEnum          `frugal:"22,optional,i64"`
   252  }
   253  ```
   254  
   255  #### Use Frugal to serialize or deserialize
   256  
   257  Example:
   258  
   259  ```go
   260  package main
   261  
   262  import (
   263      "github.com/cloudwego/frugal"
   264  )
   265  
   266  func main() {
   267      ms := &thrift.MyStruct{
   268          Msg: "my message",
   269          Code: 1024,
   270          Numbers: []int64{0, 1, 2, 3, 4},
   271      }
   272      ...
   273      buf := make([]byte, frugal.EncodedSize(ms))
   274      frugal.EncodeObject(buf, nil, ms)
   275      ...
   276      got := &thrift.MyStruct{}
   277      frugal.DecodeObject(buf, got)
   278      ...
   279  }
   280  ```