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 ```