本发明涉及跨语言调用,具体涉及一种高性能cgo跨语言调用方法。
背景技术:
1、go语言,又称golang。go语言的语法简单,易于开发,且有垃圾回收、多返回值、并发编程等高级语言特性,深受开发者欢迎。
2、go语言提供了一种名为cgo的跨语言互调机制,可以使go和c两种语言的代码互相调用,从而较为方便地复用历史遗留的、或者高性能的c代码库。然而,cgo调用的性能一直为用户所诟病,它的调用链冗长,调用开销较高。通过对go语言调用c语言中的空函数,以及对c语言重复调用n(n=1m)次go语言中的空函数进行实验,分别统计单次cgo调用的平均开销,得到如表1所示的结果。从中可见,go语言调用c语言、c语言调用go语言的开销均远高于go语言调用go语言,具体可达48倍-2707倍。
3、表1 cgo的调用开销
4、 调用方式 时间 go语言调用go语言 1.442ns go语言调用c语言 69.90ns c语言调用go语言(go语言为宿主语言) 119.749ns c语言调用go语言(c语言为宿主语言) 3904.44ns
5、这种情况主要由go语言的运行时调度模型gmp所致,运行时调度模型gmp中的g代表goroutine,即go协程,m代表machine或worker thread,即传统意义上的系统线程,p代表processor,即用户级代码逻辑处理器。如图1所示,go语言的调度单元是一个go协程,只有当系统线程m与一个逻辑处理器p关联后才能执行该逻辑处理器p队列lrq中的go协程,除非系统线程m发生阻塞或在进行系统调用时间过长时没有与之关联的逻辑处理器p。
6、在gmp模型下,若go语言的函数的运行时间过长会导致go协程被抢占,垃圾收集(gc)执行时会导致所有的go协程被挂起;而当go语言的函数调用c语言的函数时,c语言的函数的执行会限制go语言运行时的调度行为,此时会将运行c语言的系统线程m做标记,并将该系统线程m从go语言运行时的调度范围去除。
7、此外,go协程的栈空间大小是动态变化的,初始为2kb,而c语言的函数的执行可能需要一个静态未知的更大栈空间,故不适合直接在go协程的栈空间上执行c语言的函数。go语言运行时会有一个特殊go协程g0,负责对每个运行在系统线程m上的go协程进行调度和管理;特殊go协程g0在系统线程m初始化时会被分配大小固定且超过常规go协程栈的系统栈。如图2所示,当go语言的函数调用c语言的函数时,会切换到特殊go协程g0的系统栈上执行,在c语言的函数调用返回go语言的函数时需要再切换回来;这种切换是导致cgo调用开销高的主要原因。
技术实现思路
1、为解决上述技术问题,本发明提供一种高性能cgo跨语言调用方法。
2、为解决上述技术问题,本发明采用如下技术方案:
3、一种高性能cgo跨语言调用方法,对go语言跨语言互调中的逻辑处理器p和系统线程m进行惰性解绑:go语言与c语言相互调用过程中,如果go协程收到go语言发送的抢占信号时,进行如下步骤:
4、a)跳转到go语言的信号处理函数;
5、b)将当前go协程所在的逻辑处理器p和系统线程m解绑,并标记进入系统调用状态;
6、c)转到c语言的函数执行,此时所述的系统线程m被划分到go语言的运行时调度范围外;
7、d)当c语言的函数执行结束或者c语言的函数回调go语言的函数时,判断逻辑处理器p和系统线程m在c语言的函数执行前是否进行过解绑,如是,则重新绑定逻辑处理器p和系统线程m后再执行go语言的函数。
8、进一步地,包括取消go语言和c语言跨语言互调中的栈切换:
9、在go语言程序编译时,通过以下方式获取c语言的函数的栈空间使用上界spacec:用户指定、对c语言的函数执行静态分析、默认大小;
10、当go语言的函数调用c语言的函数时,根据spacec的值为执行c语言函数的go协程指示栈空间大小,使c语言的函数以及go语言的函数均可运行在go协程的同一块栈空间中。
11、与现有技术相比,本发明的有益技术效果是:
12、本发明将解绑逻辑处理器p和系统线程m这一操作从整体的跨语言调用流程中取消,只在go语言运行时尝试抢占处于hcgo调用过程中的go协程时被调用,从而能够使得在大多数情况下的跨语言调用都不需要执行这一操作;通过取消栈切换来优化跨语言调用链,降低调用开销。
1.一种高性能cgo跨语言调用方法,其特征在于,对go语言跨语言调用中的逻辑处理器p和系统线程m进行惰性解绑:go语言与c语言相互调用过程中,如果go协程收到go语言发送的抢占信号,进行如下步骤:
2.根据权利要求1所述的高性能cgo跨语言调用方法,其特征在于,包括取消go语言和c语言跨语言互调中的栈切换: