Moshi Vs Gson Vs Kotlin Serialisation
定义
- Gson
Gson 是一个Java序列化/反序列化库,用于将Java对象转换为JSON格式,以及将JSON格式转换回Java对象。
- Moshi
Moshi 是一个现代化的JSON库,适用于Android和Java。它使得将JSON解析为Java对象以及将Java对象转换回JSON变得简单。
- Kotlin序列化
Kotlin序列化是一种以Kotlin为主导的、在编译时类型安全、无反射且完全跨平台准备的序列化机制,用于将Kotlin对象转换为JSON或Protobuf等数据格式,反之亦然。该库不使用无反射,而是采用显式注解 @Serializable
。应用该注解后,编译器插件会在伴生对象上添加一个特殊的函数 serializer()
,返回类型为 KSerializer
的序列化器。KSerializer 对象实现了所需的接口,用于序列化和反序列化数据类。
性能比较
为了定义比较,创建了一个基准测试规则,可以总结如下代码片段:
class SerializableBenchMark {
lateinit var json: Json
lateinit var moshi: Moshi
lateinit var gson: Gson
lateinit var response: String
private val context = InstrumentationRegistry.getInstrumentation().targetContext
@Before
fun setup() {
json = Json {
ignoreUnknownKeys = true
isLenient = true
encodeDefaults = false
coerceInputValues = true
}
moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
gson = GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setLenient().create()
response = context.assets.open("sample_response.json").use {
it.bufferedReader().readText()
}
}
@get:Rule
val benchmarkRule = BenchmarkRule()
@Test
fun exampleKotlinSerialisation() = benchmarkRule.measureRepeated {
json.decodeFromString(Response.serializer(), response)
}
@Test
fun exampleMoshi() = benchmarkRule.measureRepeated {
val jsonAdapter = moshi.adapter(Response::class.java)
jsonAdapter.fromJson(response)
}
@Test
fun exampleGson() = benchmarkRule.measureRepeated {
gson.fromJson(response, Response.javaClass)
}
}
- 这里的
sample_response.json
是从此链接构建的。
https://www.covidvisualizer.com/api
结果
测试用例 1 — 基准测试
我已记录了每个测试用例对应的 benchmark-data.json
文件,以便进行比较。
设备详情
"build": {
"brand": "vivo",
"device": "2130",
"fingerprint": "vivo/2130i/2130:12/SP1A.210812.003/compiler05210733:user/release-keys",
"model": "V2130",
"version": {
"sdk": 31
}
},
"cpuCoreCount": 8,
"cpuLocked": true,
"cpuMaxFreqHz": 2500000000,
"memTotalBytes": 12146495488,
"sustainedPerformanceModeEnabled": false
}
Kotlin -Serialisation
"benchmarks": [
{
"name": "PROFILED_exampleKotlinSerialisation",
"params": {},
"className": "com.example.benchmark.SerializableBenchMark",
"totalRunTimeNs": 12119030155,
"metrics": {
"timeNs": {
"minimum": 3.802098385E9,
"maximum": 3.802098385E9,
"median": 3.802098385E9,
"runs": [
3.802098385E9
]
},
"allocationCount": {
"minimum": 19390.0,
"maximum": 19390.0,
"median": 19390.0,
"runs": [
19390.0,
19390.0,
19390.0,
19390.0,
19390.0
]
}
},
"sampledMetrics": {},
"warmupIterations": 2310,
"repeatIterations": 1,
"thermalThrottleSleepSeconds": 0
}
]
Moshi
"benchmarks": [
{
"name": "PROFILED_exampleMoshi",
"params": {},
"className": "com.example.benchmark.SerializableBenchMark",
"totalRunTimeNs": 11961625309,
"metrics": {
"timeNs": {
"minimum": 3.531992307E9,
"maximum": 3.531992307E9,
"median": 3.531992307E9,
"runs": [
3.531992307E9
]
},
"allocationCount": {
"minimum": 14509.0,
"maximum": 16854.0,
"median": 14509.0,
"runs": [
16854.0,
14509.0,
14509.0,
14509.0,
14509.0
]
}
},
"sampledMetrics": {},
"warmupIterations": 1202,
"repeatIterations": 1,
"thermalThrottleSleepSeconds": 0
}
]
Gson
"benchmarks": [
{
"name": "PROFILED_exampleGson",
"params": {},
"className": "com.example.benchmark.SerializableBenchMark",
"totalRunTimeNs": 1331248385,
"metrics": {
"timeNs": {
"minimum": 1.76971077E8,
"maximum": 1.76971077E8,
"median": 1.76971077E8,
"runs": [
1.76971077E8
]
},
"allocationCount": {
"minimum": 20.0,
"maximum": 20.0,
"median": 20.0,
"runs": [
20.0,
20.0,
20.0,
20.0,
20.0
]
}
},
"sampledMetrics": {},
"warmupIterations": 1062,
"repeatIterations": 1,
"thermalThrottleSleepSeconds": 0
}
]
从上面的结果可以看出,Kotlin-serialisation 花费了 12.11 秒,Moshi 花费了 11.96 秒,而 Gson 花费了 13.31 秒。
测试用例 2 — 字段不存在
在这里,我从 US 节点中移除了 name 节点,如下截图所示。
Kotlin-Serialisation测试截图如下
Moshi测试截图如下
在这种情况下,Gson 忽略了该字段并完全执行了。
对于所有这些,我们可以看到 Moshi 的错误相对于其他两者来说更具体。
测试用例 3 - 使用基准报告
单次迭代结果
5次迭代结果
结论
总体而言,在序列化/反序列化方面,Moshi 显示出了良好的结果,但 Kotlin 序列化具有 Protobuf 支持,可以帮助降低延迟和有效载荷大小,因此根据用途,人们可以谨慎选择所需的库。