Replies: 2 comments
-
这个特性依赖于组合特性,所以要等到组合特性实现之后才能开始 |
Beta Was this translation helpful? Give feedback.
0 replies
-
好吧,虽然组合还没有支持,但是我们支持了非组合的 unsafe 操作 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
需求分析
大多数时候,我们并不会考虑使用 unsafe 来直接操作对象。因为正如
unsafe
这个名字所揭示的那样,unsafe
非常危险。unsafe
完全依赖于开发者对对象在内存中布局的理解,所以从代码看上去完全看不出来每一个unsafe
操作的目标。相比之下,虽然反射也同样晦涩难明,但是至少反射依旧保留了类型、值、字段之类的信息。使用
unsafe
不仅难懂,还极难维护。每次遇到 BUG 的时候都要仔细琢磨每一个unsafe
执行的效果。很多时候这还需要手动画出内存布局,手动计算字段偏移量才能理解unsafe
操作。但是
unsafe
操作虽然有非常多的缺点,但是无可否认的就是unsafe
非常的高效。和反射比起来,它的性能要好上至少一个数量级。这主要是因为unsafe
能够极大减少 CPU 和内存分配的开支,因此 GC 的压力也会变小。场景分析
unsafe
操作对象,无非就是读写对象字段。组合场景
同时因为我们计划支持组合,所以
unsafe
也要考虑到组合的效果。在组合设计文档里面我们列举了必须要考虑的组合情况:
同样地,
unsafe
在操作对象的时候也要考虑这些情况。好在于,组合设计文档里面明显提出来不支持指针类型组合,因为在读写字段的时候基本上不需要考虑组合的结构体是 nil 的情况。
类型场景
和反射比起来,
unsafe
会操作会更加琐碎。问题的关键就在于,unsafe
本身不具备任何信息,所以一般unsafe
都要结合反射的类型信息进行使用。反射的类型信息主要用于辅助unsafe
在读写字段的时候编解码。因此要充分考虑不同类型带来的影响,这些类型已经罗列在支持类型中
功能需求
可以默认组合不会有指针类型的组合,
eorm
的其它模块会确保这一点。unsafe
来读写字段unsafe
来读写组合内部字段unsafe
来读写支持类型中的所有类型非功能需求
设计
unsafe
操作主要影响两个地方。首先是在元数据解析那里,要计算字段的偏移量。这个偏移量是指针对最外面的一层的偏移量,例如:除此以外,另外一个要修改的地方就是
value
包,以及对不同类型的编解码。详细设计
元数据解析
类似地,我们在列元数据里面加一个字段
offset
,代表偏移量:Offset 的计算规则比较简单,例如:
那么
Field2
的偏移量为:offset = offset(B->A) + offset(C->B) + offset(Field2->C)即
Field2
的偏移量为 B 相对于 A 的偏移量,C 相对于 B 的偏移量,Field2
相对于 C 的偏移量三者之和。只需要在已有的逻辑基础上稍微做修改就可以。
Value
Value
的实现也是很简单。在已经计算出来偏移量的情况下,基本上就是直接读取:正如我们前面所说,
unsafe
本身没有任何类型信息,所以我们需要利用反射的Type
,并且结合switch-case
来处理不同类型。其次还要考虑:byte
,其它的都是非法的driver.Valuer
接口和sql.Scanner
接口,那么它们的处理会更加棘手测试
单元测试
单元测试要覆盖功能需求里面的场景:
同时要考虑这些场景混合在一起:
集成测试
N/A。
基准测试
提供
unsafe
在不同组合形态下的基准测试不同类型主要影响的是编解码过程,所以要对编解码进行基准测试。
模糊测试
unsafe
进行模糊测试Beta Was this translation helpful? Give feedback.
All reactions