这是一篇两年前的文章 ( Golang 反射性能优化 - 知乎 (zhihu.com) ) 的后记。
在当时那一篇文章中,主要讲了如何去优化反射,优化reflect.Set中性能损耗的原理,以及对reflect.New()的性能继续调优的思路。
在Golang泛型发布之后(1.18发布了泛型,现在1.20了我才想起来这篇文章),我又在当时的思路下做了新的尝试,并且目前尝试算是成功,这才有了后续的这一篇文章。
unsafe

思路分析

在上一篇文章的最后,我们提出了一个思路:

  • 值类型传递值时会进行拷贝

我们可以尝试通过这个特性来获得一个原生级别的对象拷贝,再对新值中的成员变量进行赋值,来获得一个近似原生级别的对象创建。

我们可以创建一个简单的函数来展示这一点特性:

myCopy()
interface{}interface{}interface{}
interface{}interface{}

这是因为在第四行:

在这里的时候,传递了值,所以对结构体进行了拷贝。

interface{}
case1Peoplecase2Peopleinterface{}p1p2inp3
myCopy

原理与实现

在我们讲实现之前,我需要先讲一下在Go中泛型的原理。

泛型原理

泛型大多由这两种方式之一实现:

sortSortXxx()

在Go中,官方综合了两种方式,对于值类型使用单态化的方式实现,对于指针类型和接口类型则使用虚函数表的方式实现。

干掉 unsafe_new()

unsafe_new()

Go中另一个特性是当我们创建一个变量时,如果该变量是值类型,则自动为其赋空值。于是我们可以给函数的返回值命名,直接修改返回值变量的值。这样的好处是我们操作的值完全为一个新的值,传入值中成员变量的值不会造成影响。

以下是实现的样例,我们实现了两个函数,一个是获得某个类型的值,另一个是获得某一个类型的新指针:

unsafe_New()

Benchmark

新创建两个函数,对两个新函数进行测试:

(其余的测试函数可以在上一篇文章找到)

运行之后,结果如我们所愿:

我们可以看到,新函数与原生的性能相似,我们完美达到了我们的目的。

END

工作以后没有多少时间写文章,写自己的东西了。(其实也不是工作太忙,而是需求太不饱和,太容易摸鱼,并且生活中快乐的事情太多,想不起来写代码写文章。)泛型已经发布了有一段时间了,但是我还没有实际用上。在前两天突然有了灵感,想起来了这一点,于是去做了一些尝试,并且发现成功了,才补上了这一篇文章。

诚然,如果要让反射系统用上泛型来优化,需要做相当多的改动,并且大部分的系统的瓶颈也不会在反射上,这一篇文章也只是在以玩玩具的心态,边研究Go的内存模型边做的。

写代码真好玩。