为了账号安全,请及时绑定邮箱和手机立即绑定

性能:排序切片与排序类型(切片)与排序实现

性能:排序切片与排序类型(切片)与排序实现

Go
小怪兽爱吃肉 2023-06-01 17:14:29
我正在处理一些代码挑战,发现自定义排序(排序接口的实现)比仅针对切片的原始结构工作得更快。这是为什么?切片转换为类型是否有一些魔力(比如转换为结构指针的切片)?我做了一些代码来测试我的 hipotesispackage sortingexampleimport (    "sort"    "testing")// Example of struct we going to sort.type Point struct {    X, Y int}// --- Struct / Raw Datavar TestCases = []Point{    {10, 3},    {10, 4},    {10, 35},    {10, 5},    {10, 51},    {10, 25},    {10, 59},    {10, 15},    {10, 22},    {10, 91},}// Example One - Sorting Slice Directly// somehow - slowest way to sort it.func SortSlice(points []Point) {    sort.Slice(points, func(i, j int) bool {        return points[i].Y < points[j].Y    })}func BenchmarkSlice(b *testing.B) {    tmp := make([]Point, len(TestCases))    for i := 0; i < b.N; i++ {        copy(tmp, TestCases)        SortSlice(tmp)    }}// Example Two - Sorting Slice Directly// much faster performancetype Points []Point// Sort interface implementationfunc (p Points) Less(i, j int) bool { return p[i].Y < p[j].Y }func (p Points) Len() int           { return len(p) }func (p Points) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }func SortStruct(points []Point) {    sort.Sort(Points(points))}func BenchmarkStruct(b *testing.B) {    tmp := make([]Point, len(TestCases))    for i := 0; i < b.N; i++ {        copy(tmp, TestCases)        SortStruct(tmp)    }}// --- Pointersvar TestCasesPoints = []*Point{    &Point{10, 3},    &Point{10, 4},    &Point{10, 35},    &Point{10, 5},    &Point{10, 51},    &Point{10, 25},    &Point{10, 59},    &Point{10, 15},    &Point{10, 22},    &Point{10, 91},}// Example Three - Sorting Slice of Pointersfunc SortSlicePointers(points []*Point) {    sort.Slice(points, func(i, j int) bool {        return points[i].Y < points[j].Y    })}func BenchmarkSlicePointers(b *testing.B) {    tmp := make([]*Point, len(TestCasesPoints))    for i := 0; i < b.N; i++ {        copy(tmp, TestCasesPoints)        SortSlicePointers(tmp)    }}很明显,对指针切片进行排序会更快,但是为什么自定义排序实现会更快呢?有什么我可以阅读的资源吗?
查看完整描述

2 回答

?
九州编程

TA贡献1785条经验 获得超4个赞

一般sort.Slice()sort.SliceStable()功能适用于任何切片。您必须将切片值作为interface{}值传递,并且实现必须使用反射(reflect包)来访问其元素和长度,并执行元素交换。

相反,当你sort.Interface自己实现类型时,在你的实现中你可以访问你的切片的静态类型,并且你可以提供没有sort.Interface反射的实现,这将使它更快。

因此,如果性能很关键/很重要,请始终sort.Interface自己提供实现。如果切片很小或性能不重要,您可以使用更方便的sort.Slice()功能。


查看完整回答
反对 回复 2023-06-01
?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

添加带有分配的运行输出看起来接口/结构方法也更好。


❯ go version

go version go1.17.1 darwin/amd64

❯ go test -bench=. -benchmem

goos: darwin

goarch: amd64

pkg: github.com/timescale/promscale/pkg/api/parser/json/test

cpu: Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz

BenchmarkSlice-12                        3533616               319.6 ns/op            88 B/op          3 allocs/op

BenchmarkStruct-12                       9157018               126.0 ns/op            24 B/op          1 allocs/op

BenchmarkSlicePointers-12                6643446               167.1 ns/op            56 B/op          2 allocs/op

BenchmarkStructOfSlicePointers-12        9004021               124.1 ns/op            24 B/op          1 allocs/op

PASS

ok      github.com/timescale/promscale/pkg/api/parser/json/test 5.425s


查看完整回答
反对 回复 2023-06-01
  • 2 回答
  • 0 关注
  • 159 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信