怎么让Go语言中的反射加快


这篇文章主要介绍“怎么让Go语言中的反射加快”,在日常操作中,相信很多人在怎么让Go语言中的反射加快问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么让Go语言中的反射加快”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!我们以一个简单的案例为切入点,定义一个结构体SimpleStruct,它包括两个 int 类型字段A和B。假如我们接收到了 JSON 数据 {“B”: 42},想要对其进行解析并且将字段B设置为 42。在下文,我们将编写一些函数来实现这一点,它们都会将 B 设置为 42。如果我们的代码只适用于 SimpleStruct,这完全是不值一提的。但是,如果我们是要做一个 JSON 解析器,这意味着我们并不能提前知道结构类型。我们的解析器代码需要接收任何类型的数据。在 Go 中,这通常意味着需要采用 interface{} (空接口)参数。然后我们可以使用 reflect 包检查通过空接口参数传入的值,检查它是否是指向结构体的指针,找到字段B并用我们的值填充它。代码将如下所示。让我们通过基准测试看看它有多快。结果如下。BenchmarkPopulateReflect-16 15941916 68.3 ns/op 8 B/op 1 allocs/op这是好还是坏?好吧,内存分配可从来不是好事。你可能想知道为什么需要在堆上分配内存来将结构体字段设置为 42。但总体而言,68ns 的时间并不长。在通过网络发出任何类型的请求时间中,你可以容纳很多 68ns。我们能做得更好吗?好吧,通常我们运行的程序不会只做一件事然后停止。他们通常一遍又一遍地做着非常相似的事情。因此,我们可以设置一些东西以使重复的事情速度变快吗?如果仔细查看我们正在执行的反射检查,我们会发现它们都取决于传入值的类型。如果我们将类型结果缓存起来,那么对于每种类型而言,我们只会进行一次检查。我们再来考虑内存分配的问题。之前我们调用Value.FieldByName方法,实际是Value.FieldByName调用Type.FieldByName,其调用structType.FieldByName,最后调用structType.Field来引起内存分配的。我们可以在类型上调用FieldByName并缓存一些东西来获取B字段的值吗?实际上,如果我们缓存Field.Index,就可以使用它来获取字段值而无需分配。新代码版本如下因为没有任何内存分配,新的基准测试变得更快。BenchmarkPopulateReflectCache-16 35881779 30.9 ns/op 0 B/op 0 allocs/op我们能做得更好吗?好吧,如果我们知道结构体字段 B 的偏移量并且知道它是 int 类型,就可以将其直接写入内存。我们可以从接口中恢复指向结构体的指针,因为空接口实际上是具有两个指针的结构的语法糖:第一个指向有关类型的信息,第二个指向值。我们可以使用结构体中字段偏移量来直接寻址该值的字段 B。新代码如下。新的基准测试表明这将更快。BenchmarkPopulateUnsafe-16 62726018 19.5 ns/op 0 B/op 0 allocs/op还能让它走得更快吗?如果我们对 CPU 进行采样,将会看到大部分时间都用于访问 map,它还会显示 map 访问在调用runtime.interhash和runtime.interequal。这些是用于 hash 接口并检查它们是否相等的函数。也许使用更简单的 key 会加快速度?我们可以使用来自接口的类型信息的地址,而不是reflect.Type本身。这是新版本的基准测试结果,它又快了很多。BenchmarkPopulateUnsafe2-16 230836136 5.16 ns/op 0 B/op 0 allocs/op还能更快吗?通常如果我们要将数据 unmarshaling 到结构体中,它总是相同的结构。因此,我们可以将功能一分为二,其中一个函数用于检查结构是否符合要求并返回一个描述符,另外一个函数则可以在之后的填充调用免费云主机域名中使用该描述符。以下是我们的新代码版本。调用者应该在初始化时调用describeType函数以获得一个typeDescriptor,之后调用populateStructUnsafe3函数时会用到它。在这个非常简单的例子中,typeDescriptor只是结构体中B字段的偏移量。以下是如何使用describeType调用的新基准测试。现在基准测试结果变得相当快。BenchmarkPopulateUnsafe3-16 1000000000 0.359 ns/op 0 B/op 0 allocs/op这有多棒?如果我们以文章开头原始的populateStruct函数编写基准测试,可以看到在不使用反射的情况下,填充这个结构体的速度有多快。BenchmarkPopulate-16 1000000000 0.234 ns/op 0 B/op 0 allocs/op不出所料,这甚至比我们最好的基于反射的版本还要快一点,但它也没有快太多。到此,关于“怎么让Go语言中的反射加快”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注百云主机网站,小编会继续努力为大家带来更多实用的文章!

相关推荐: Vue-loader如何使用

本文小编为大家详细介绍“Vue-loader如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Vue-loader如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。Vue-loader其实就是一个webpack的loade…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

Like (0)
Donate 微信扫一扫 微信扫一扫
Previous 03/31 15:15
Next 03/31 15:15

相关推荐