mmap.dev

reflect.Swapper の恩恵をうけたslice utility

Published on

標準のsort package では reflect.Swapper を利用した sort.Slice の 登場でだいぶ高速化された。

で自分でもslice を使って恩恵にあずかろうということで Select とかFilter とか Uniq みたいなもので具体的につくってみた (つくったのはちょっと前だが)

それが loncha ってやつです

linked-list もこのpackage に含まれているんだけど… go-funk がもってるようなものを高速化して実装してみたというかんじ

まず slice のデータ定義して

    import "github.com/kazu/loncha"

    type GameObject struct {
        ID int
        Name string
        Pos []float
    }

    ...

Find,Filder,Delete, Select, Shuffle とか

   var objs []GameObject

    loncha.Find(&objs, func(i int) bool {
        return objs[i].ID == 6
    } 

    loncha.Filter(&objs, func(i int) bool {
        return objs[i].ID == 12
    } 

	loncha.Delete(&objs, func(i int) bool {
		return objs[i].ID == 555
	})

    // find one object with conditions.
    obj, err := Select(&objs, func(i int) bool {
		return slice[i].ID < 50
	})

    err = loncha.Shuffle(objs, 2)

sort.Slice と同じで 条件関数にinterface/reflect.ValueOf がからむと とたんに遅くなるので index だけ渡す感じにしてます。で中の処理は

movelist で移動するindex をいれておいて

movelist := make([]int, length)
... なんらかの処理

	swap := reflect.Swapper(pRv.Elem().Interface())

	for i, v := range movelist {
		if v != -1 {
			swap(i, v)
		}
	}

reflect.Swapper でslice の中身をバキュンて交換してます。

いちよ てで行った処理とgo-funkloncha のベンチマークも軽くとってます

loncha.Uniq-16         	    			1000	    997543 ns/op	  548480 B/op	   16324 allocs/op
loncha.UniqWithSort-16 	    			1000	   2237924 ns/op	     256 B/op	       7 allocs/op
loncha.UniqWithSort(sort)-16         	1000	    260283 ns/op	     144 B/op	       4 allocs/op
hand_Uniq-16                          	1000	    427765 ns/op	  442642 B/op	       8 allocs/op
hand_Uniq_iface-16                    	1000	    808895 ns/op	  632225 B/op	    6322 allocs/op
go-funk.Uniq-16                       	1000	   1708396 ns/op	  655968 B/op	   10004 allocs/op

pointer ってあるのは slice の要素をポインタにしたとき

loncha.Filter-16         	     100	     89142 ns/op	   82119 B/op	       4 allocs/op
loncha.Filter_pointer-16 	     100	       201 ns/op	       0 B/op	       0 allocs/op
hand_Filter_pointer-16   	     100	     24432 ns/op	   81921 B/op	       1 allocs/op
go-funk.Filter-16        	     100	   2370492 ns/op	  640135 B/op	   20004 allocs/op
go-funk.Filter_pointer-16        100	      1048 ns/op	      64 B/op	       2 allocs/op

ポインタでも4倍ぐらいはやいが。実体だと条件関数に実体わたすのもあるし20倍以上ちがう

comments powered by Disqus