C调用LUA各种方式的性能对比

测试环境

i5-3470 @ 3.20G 3.70G,Windows,lua5.3,程序运行在单核单线程上。

Lua脚本

function lua_callback()
end

function reg()
set_callback(lua_callback)
end

lua_callback是主要测试对象,是个空函数,reg是Lua向C注册回调。

C测试代码

#include "stdio.h"
#include <string>
#include <windows.h>

extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

lua_State *L_ = NULL;
int lua_callback_ = LUA_REFNIL;

LONGLONG get_tickcount() {
LARGE_INTEGER freq,counter;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&counter);
return (1000000L * counter.QuadPart / freq.QuadPart)/1000L;
}

std::string load_test_lua() {
std::string lua_buff;
FILE *fp = fopen("test.lua","rb");
if (fp == NULL) {
return "";
}

fseek(fp, 0, SEEK_END);
int size = ftell(fp);
fseek(fp, 0, SEEK_SET);
lua_buff.resize(size);
fread((void*)lua_buff.data(), size, 1, fp);
fclose(fp);
return lua_buff;
}

int set_callback(lua_State *L) {
int ret = -1;
do {
int callback = (int)luaL_ref(L, LUA_REGISTRYINDEX); //将栈顶回调放入lua注册表获并取引用
if (callback == LUA_REFNIL) {
break;
}

lua_callback_ = callback; //保存回调函数的引用
ret = 0;
} while (0);
return ret;
}

void register_function(lua_State *L) {
lua_register(L, "set_callback", set_callback); //注册函数,lua->C
}

int reg(lua_State *L) {
lua_State *co = lua_newthread(L);
lua_getglobal(co, "reg");
int rs = lua_resume(co, L, 0);
return rs;
}

int call1(lua_State *L) {
lua_State *co = lua_newthread(L);
lua_getglobal(co, "lua_callback");
int rs = lua_resume(co, L, 0);
lua_pop(L,1); //co留在主线程的栈上,必须pop,否则栈会溢出
return rs;
}

int call2(lua_State *L) {
lua_State *co = lua_newthread(L);
lua_rawgeti(co, LUA_REGISTRYINDEX, lua_callback_);
int rs = lua_resume(co, L, 0);
lua_pop(L,1); //co留在主线程的栈上,必须pop,否则栈会溢出
return rs;
}

int call3(lua_State *L) {
lua_rawgeti(L, LUA_REGISTRYINDEX, lua_callback_);
int rs = lua_pcall(L, 0, 0, 0);
return rs;
}

int call4(lua_State *L) {
lua_getglobal(L, "lua_callback");
int rs = lua_pcall(L, 0, 0, 0);
return rs;
}

LONGLONG test_call(int type, int count, lua_State *L) {
LONGLONG s = get_tickcount();
switch (type) {
case 1: {
for (int i = 0; i < count;i++) {
call1(L);
}
break;
}
case 2: {
for (int i = 0; i < count;i++) {
call2(L);
}
break;
}
case 3: {
for (int i = 0; i < count;i++) {
call3(L);
}
break;
}
case 4: {
for (int i = 0; i < count;i++) {
call4(L);
}
break;
}
}

LONGLONG e = get_tickcount();
return e - s;
}

int main()
{
L_ = luaL_newstate();

luaL_openlibs(L_);
register_function(L_);
std::string lua_buffer = load_test_lua();
int rs = (luaL_loadbuffer(L_, lua_buffer.c_str(), lua_buffer.length(), "test") || lua_pcall(L_, 0, LUA_MULTRET, 0));
if (rs != LUA_OK) {
return 0;
}

reg(L_);

int count = 1000000;
LONGLONG s1 = test_call(1, count, L_);
LONGLONG s2 = test_call(2, count, L_);
LONGLONG s3 = test_call(3, count, L_);
LONGLONG s4 = test_call(4, count, L_);
printf("coroutine+no register callback=%I64dms\n",s1);
printf("coroutine+register callback=%I64dms\n",s2);
printf("no coroutine+register callback=%I64dms\n",s3);
printf("no coroutine+no register callback=%I64dms\n",s4);
getchar();
return 0;
}


测试结果

测试1000000次
coroutine+no register callback=21745ms //启动协程,直接通过lua函数名调用,每个调用需要0.02ms左右
coroutine+register callback=21519ms //启动协程,通过lua注册表中的回调调用
no coroutine+register callback=567ms //不启动协程,在主线程通过lua注册表中的回调调用,每个调用需要0.6us左右
no coroutine+no register callback=674ms //不启动协程,在主线程通过lua函数名直接调用

结论

可以看出通过lua函数名调用和通过注册表注册lua回调的性能差距不大,每个调用大概差距在0.1us左右。
但是通过协程调用与不使用协程调用性能差距达到35倍左右。

猜你喜欢

转载自blog.csdn.net/sonysuqin/article/details/78552831
今日推荐