Lua의 코루틴을 여러가지 방법으로 만들어 실행해 본다 in C++ (이어서 시간도 측정한다)

14755 단어 C++luabind루아
현재 C++, Lua, luabind를 사용하여 게임 등 만들고 놀고 있습니다. Lua의 코루틴을 자주 사용합니다만, 코루틴의 작성은 상당히 느린 처리라고 하는 것을 어딘가에서 읽고, 신경이 쓰였습니다.

코루틴의 작성 방법·실행 방법은 몇 가지가 있으므로, 그 평소 사용하고 있지 않는 방법도 시험해 보는 김에에 시간도 측정해 보았습니다.

소스 코드



coro.lua
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

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의 영향이 더 큰 것처럼 보입니다.


실행 환경


  • Core i5-4570 3.2GHz
  • RAM 8GB
  • Windows 7 64bit SP1
  • Visual Studio Community 2015 Update 1
  • Lua 5.1.5 (x64)
  • luabind 0.9

  • 참고로 한 사이트


  • Lua 5.1 참조 매뉴얼
  • 코루틴 사용
  • C++에서 자유 플랫폼 시간 측정

  • 이 기사를 쓰고 신경이 쓰인 것



    ・처리 속도적으로는 매회 lua_newthread 불러도 별로 좋은 생각이 든다
     →스택 상한에 곧 도달할 것 같다
     →지금까지는 스레드 1000개 정도 스택에 쌓아 사용 돌리는 느낌으로 부족했기 때문에 신경쓰지 않았다
     →정말 대량으로 사용하고 싶은 경우는 thread를 스택으로부터 레지스트리에 옮기거나 할 필요가 있을지도 있을지도 (조사하고 있지 않다)
    이쪽 가 써 계시는 「코루틴의 이용」의 기사에 있는 것 같은, 건네받은 함수를 무한하게 실행할 뿐의 코루틴을 대량으로 만들어 놓고 사용 돌리는 방법도 시험해 보고 싶었다(귀찮은 그래서 어쩔 수 없어…)

    좋은 웹페이지 즐겨찾기