Golang骚操作——使用runtime私有函数

20 篇文章 4 订阅

在Golang中,变量、函数、结构体等访问权限是由标识符的首字母大小写决定的,首字母小写的变量等在其它包中是不可见的,那么我们如何才能使用它们呢?这就需要使用一些骚操作了。

        说起Golang的入口函数,我们都会认为是main.main,但是在Golang程序启动前,需要先执行runtime.main来初始化调度器、垃圾回收器等。在proc.go文件中我们可以找到这样一行代码:

//go:linkname main_main main.main
func main_main()

        这个main_main函数没有函数体,在链接的时候,编译器会将其链接到我们自己的main函数,然后由runtime.main来调用。
        上面的一行正是编译器指令,就行C/C++中的#开头的编译指令,在Go中使用 //go:来表示,使用//go:linkname指示在编译时将该函数链接到其它函数,也就是将main_main链接到main.main。
        因此我们也可以使用这个编译器指令将函数链接到runtime中的私有函数。

 

memmove

// memmove copies n bytes from "from" to "to".
func memmove(to, from unsafe.Pointer, n uintptr)

        memmove像是C语言中的memcpy函数,它可以进行内存拷贝,但是它是小写开头的,因此我们需要使用编译器指令才能使用:
        在我们的文件中先进行一个声明:

然后我们就可以使用它了,我们可以实现一个切片拷贝的函数,在这里使用Go1.18的泛型:
在这里插入图片描述
最后,来测试一下这个函数与直接一个一个赋值来拷贝的方式进行一个对比测试:

// 使用memmove来拷贝切片
func SliceClone[T BaseType](s []T) []T {
	res := make([]T, len(s), cap(s))
	sptr := (*Slice)(unsafe.Pointer(&s))
	resptr := (*Slice)(unsafe.Pointer(&res))
	var tmp T
	memmove(resptr.Ptr, sptr.Ptr, unsafe.Sizeof(tmp) * uintptr(sptr.Len))
	resptr.Len = sptr.Len

	return res
}


// 一个个赋值拷贝切片
func SliceCopy[T BaseType](s []T) []T {
	res := make([]T, len(s), cap(s))
	for i := 0; i < len(s); i++ {
		res[i] = s[i]
	}

	return res
}

// 使用内置copy来拷贝切片
func SliceCopyBuildIn[T BaseType](s []T) []T {
	res := make([]T, len(s), cap(s))
	copy(res, s)

	return res
}

测试:


func BenchmarkSliceClone(b *testing.B) {
	sc := make([]int, 10000)
	for i := 0; i < 10000; i++ {
		sc[i] = i
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		SliceClone(sc)
	}
}

func BenchmarkSliceCopy(b *testing.B) {
	sc := make([]int, 10000)
	for i := 0; i < 10000; i++ {
		sc[i] = i
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		SliceCopy(sc)
	}
}

func BenchmarkSliceCopyBuildIn(b *testing.B) {
	sc := make([]int, 10000)
	for i := 0; i < 10000; i++ {
		sc[i] = i
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		SliceCopyBuildIn(sc)
	}
}

结果:

$ go test -bench=.
goos: windows
goarch: amd64
pkg: code/go_scheduler_analyse
cpu: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz
BenchmarkSliceClone-8             115420             10169 ns/op
BenchmarkSliceCopy-8              101098             11957 ns/op
BenchmarkSliceCopyBuildIn-8       118712             10069 ns/op
PASS
ok      code/go_scheduler_analyse       4.111s


可以看到,可能还不如内置的copy速度快,挺鸡肋的。。。。
但是我们可以用来实现字符串和切片的拷贝:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值