Lua의 코루틴을 여러가지 방법으로 만들어 실행해 본다 in C++ (이어서 시간도 측정한다)
코루틴의 작성 방법·실행 방법은 몇 가지가 있으므로, 그 평소 사용하고 있지 않는 방법도 시험해 보는 김에에 시간도 측정해 보았습니다.
소스 코드
coro.lualocal a = 0
function coro_func()
for i=1, 100 do
a = a + math.random()
coroutine.yield(0)
end
return 1 --コルーチンが終了したら1を返す仕様
end
function run_coroutine_lua()
local coro = coroutine.create(coro_func)
repeat
ret1, ret2 = coroutine.resume(coro)
until ret2 == 1
end
function print_a()
print(a)
a = 0
end
luathread.cpp#include <iostream>
#include <chrono>
#include <lua.hpp>
#include <luabind/luabind.hpp>
#include <luabind/object.hpp>
using namespace std;
const int STACKSIZE = 5100;
const int N = 5000; // 繰り返し回数
lua_State* init_lua()
{
lua_State* L = lua_open();
luaL_openlibs(L);
lua_checkstack(L, STACKSIZE);
luaL_dofile(L, "coro.lua");
return L;
}
// 時間測る用
void print_elapsed(chrono::system_clock::time_point start)
{
cout << chrono::duration_cast<chrono::milliseconds>
(chrono::system_clock::now() - start).count() << ",";
}
int main()
{
lua_State* L = init_lua();
lua_State* thread;
// ◆パターン1:Lua側でコルーチンを作って実行する
auto start = chrono::system_clock::now();
for (int i = 0; i < N; i++) {
luabind::call_function<void>(L, "run_coroutine_lua");
}
print_elapsed(start);
// ◆パターン2:C++側でコルーチンを作って実行する
start = chrono::system_clock::now();
thread = lua_newthread(L);
for (int i = 0; i < N; i++) {
lua_getglobal(thread, "coro_func");
int ret = 0;
while (ret == 0) {
lua_resume(thread, 0);
ret = lua_tointeger(thread, -1);
}
}
print_elapsed(start);
// ◆パターン3:C++側でコルーチンを作って実行する(luabind)
start = chrono::system_clock::now();
thread = lua_newthread(L);
for (int i = 0; i < N; i++) {
int ret = luabind::resume_function<int>(thread, "coro_func");
while (ret != 1) {
ret = luabind::resume<int>(thread);
}
}
print_elapsed(start);
// ◆パターン4:C++側でコルーチンを作って実行する
//(lua_newthreadを毎回呼ぶ、遅そうだが…)
start = chrono::system_clock::now();
for (int i = 0; i < N; i++) {
thread = lua_newthread(L);
int ret = luabind::resume_function<int>(thread, "coro_func");
while (ret != 1) {
ret = luabind::resume<int>(thread);
}
}
print_elapsed(start);
cout << "\n";
lua_close(L);
return 0;
}
소스 코드의 내용에 대해
코루틴이 끝날 때까지 resume 하는 처리를 N회 반복해 그 시간을 측정하고 있습니다. 코루틴의 내용은 적당합니다.
・패턴 1:Lua측에서 코루틴을 만들어 실행한다
매번 coroutine.create로 코루틴을 만들어 실행하고 있습니다. 정말 늦어 보인다.
・패턴 2:C++측에서 코루틴을 만들어 실행한다(1)
lua_newthread로 스레드를 만들고 lua_resume에서 실행하고 있습니다.
코루틴이 종료한 후, 새롭게 lua_newthread를 부를 필요는 실은 없네요. 이미 종료한 thread를 lua_resume 에 건네주면 다시 처음부터 실행할 수 있습니다.
・패턴 3:C++측에서 코루틴을 만들어 실행한다(2)
내가 평소 사용하고있는 luabind에 의한 방법입니다. 스택의 상태라든지 별로 생각하지 않아도 좋기 때문에 편합니다.
・패턴 4:C++측에서 코루틴을 만들어 실행한다(3)
패턴 1과 같은 느낌으로 lua_newthread를 매번 불러 보았습니다.
처리 시간의 측정 결과
위의 프로그램을 100회 실행하여 처리 시간의 그래프를 그려 보았습니다.
예상대로 패턴 1 (Lua)는 다른 것보다 느립니다. 그러나 패턴 2~4는 거기까지 차이가 없습니다.
lua_newthread보다 luabind의 영향이 더 큰 것처럼 보입니다.
실행 환경
local a = 0
function coro_func()
for i=1, 100 do
a = a + math.random()
coroutine.yield(0)
end
return 1 --コルーチンが終了したら1を返す仕様
end
function run_coroutine_lua()
local coro = coroutine.create(coro_func)
repeat
ret1, ret2 = coroutine.resume(coro)
until ret2 == 1
end
function print_a()
print(a)
a = 0
end
#include <iostream>
#include <chrono>
#include <lua.hpp>
#include <luabind/luabind.hpp>
#include <luabind/object.hpp>
using namespace std;
const int STACKSIZE = 5100;
const int N = 5000; // 繰り返し回数
lua_State* init_lua()
{
lua_State* L = lua_open();
luaL_openlibs(L);
lua_checkstack(L, STACKSIZE);
luaL_dofile(L, "coro.lua");
return L;
}
// 時間測る用
void print_elapsed(chrono::system_clock::time_point start)
{
cout << chrono::duration_cast<chrono::milliseconds>
(chrono::system_clock::now() - start).count() << ",";
}
int main()
{
lua_State* L = init_lua();
lua_State* thread;
// ◆パターン1:Lua側でコルーチンを作って実行する
auto start = chrono::system_clock::now();
for (int i = 0; i < N; i++) {
luabind::call_function<void>(L, "run_coroutine_lua");
}
print_elapsed(start);
// ◆パターン2:C++側でコルーチンを作って実行する
start = chrono::system_clock::now();
thread = lua_newthread(L);
for (int i = 0; i < N; i++) {
lua_getglobal(thread, "coro_func");
int ret = 0;
while (ret == 0) {
lua_resume(thread, 0);
ret = lua_tointeger(thread, -1);
}
}
print_elapsed(start);
// ◆パターン3:C++側でコルーチンを作って実行する(luabind)
start = chrono::system_clock::now();
thread = lua_newthread(L);
for (int i = 0; i < N; i++) {
int ret = luabind::resume_function<int>(thread, "coro_func");
while (ret != 1) {
ret = luabind::resume<int>(thread);
}
}
print_elapsed(start);
// ◆パターン4:C++側でコルーチンを作って実行する
//(lua_newthreadを毎回呼ぶ、遅そうだが…)
start = chrono::system_clock::now();
for (int i = 0; i < N; i++) {
thread = lua_newthread(L);
int ret = luabind::resume_function<int>(thread, "coro_func");
while (ret != 1) {
ret = luabind::resume<int>(thread);
}
}
print_elapsed(start);
cout << "\n";
lua_close(L);
return 0;
}
코루틴이 끝날 때까지 resume 하는 처리를 N회 반복해 그 시간을 측정하고 있습니다. 코루틴의 내용은 적당합니다.
・패턴 1:Lua측에서 코루틴을 만들어 실행한다
매번 coroutine.create로 코루틴을 만들어 실행하고 있습니다. 정말 늦어 보인다.
・패턴 2:C++측에서 코루틴을 만들어 실행한다(1)
lua_newthread로 스레드를 만들고 lua_resume에서 실행하고 있습니다.
코루틴이 종료한 후, 새롭게 lua_newthread를 부를 필요는 실은 없네요. 이미 종료한 thread를 lua_resume 에 건네주면 다시 처음부터 실행할 수 있습니다.
・패턴 3:C++측에서 코루틴을 만들어 실행한다(2)
내가 평소 사용하고있는 luabind에 의한 방법입니다. 스택의 상태라든지 별로 생각하지 않아도 좋기 때문에 편합니다.
・패턴 4:C++측에서 코루틴을 만들어 실행한다(3)
패턴 1과 같은 느낌으로 lua_newthread를 매번 불러 보았습니다.
처리 시간의 측정 결과
위의 프로그램을 100회 실행하여 처리 시간의 그래프를 그려 보았습니다.
예상대로 패턴 1 (Lua)는 다른 것보다 느립니다. 그러나 패턴 2~4는 거기까지 차이가 없습니다.
lua_newthread보다 luabind의 영향이 더 큰 것처럼 보입니다.
실행 환경
참고로 한 사이트
이 기사를 쓰고 신경이 쓰인 것
・처리 속도적으로는 매회 lua_newthread 불러도 별로 좋은 생각이 든다
→스택 상한에 곧 도달할 것 같다
→지금까지는 스레드 1000개 정도 스택에 쌓아 사용 돌리는 느낌으로 부족했기 때문에 신경쓰지 않았다
→정말 대량으로 사용하고 싶은 경우는 thread를 스택으로부터 레지스트리에 옮기거나 할 필요가 있을지도 있을지도 (조사하고 있지 않다)
・ 이쪽 가 써 계시는 「코루틴의 이용」의 기사에 있는 것 같은, 건네받은 함수를 무한하게 실행할 뿐의 코루틴을 대량으로 만들어 놓고 사용 돌리는 방법도 시험해 보고 싶었다(귀찮은 그래서 어쩔 수 없어…)
Reference
이 문제에 관하여(Lua의 코루틴을 여러가지 방법으로 만들어 실행해 본다 in C++ (이어서 시간도 측정한다)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/voidProc/items/e0ae560afe3cfb9e8808
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(Lua의 코루틴을 여러가지 방법으로 만들어 실행해 본다 in C++ (이어서 시간도 측정한다)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/voidProc/items/e0ae560afe3cfb9e8808텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)