www.mudconnector.su
http://forum.mudconnector.su/

mud design-concepts (расширяемость)
http://forum.mudconnector.su/viewtopic.php?f=16&t=244
Страница 2 из 3

Автор:  omlin [ Пт ноя 19, 2010 10:27 pm ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

Эрендир, всё-таки вы неверно поняли, видимо
Lua - это встраиваемый язык, он существует в контексте вашего приложения, и следовательно, вы должны с ним взаимодействовать.

Именно для этого предназначено Lua C API

Когда вы хотите выполнить в Lua код
Код:
foo={}
for i = 1, 10^6 do
   foo.bar=10
end


из вашего C-приложения, вы должны написать:

Код:
char *code = "for i = 1, 10^6 do foo.bar = 10 end";
luaL_dostring(luaState, code);

Справка по lua_dostring

и это действительно будет выполняться недолго
почему?
потому что, надо понимать, что здесь происходит на самом деле:
1) вызов библиотеки луа, передача в неё одной строки (на это на самом деле тоже тратится время)
2) луа парзит строку (на это тратится время!!), но т.к. строка в данном случае недлинная, парзится она довольно быстро, и преобразуется в байт-код
3) луа выполняет полученный байт-код, и на это тоже тратится время, впрочем это уже происходит очень быстро

но наша задача в другом
наша задача заключается в том, чтобы передать наши объекты в луа
к примеру, у нас в c есть некий объект foo, у него есть свойство-массив с миллионом элементов:
int Bar[1000000];
мы должны создать такой же объект в луа
мы можем сделать это примерно так:

Код:
sprintf(code, "
  foo = {}
  foo.Bar[0] = %d
  foo.Bar[1] = %d
  foo.Bar[2] = %d
  foo.Bar[3] = %d
  foo.Bar[4] = %d
  --- ....
  foo.Bar[999999] = %d", foo.Bar[0], foo.Bar[1], foo.Bar[2], foo.Bar[3], ... foo.Bar[999999]);

luaL_dostring(luaState, code);


представьте, сколько луа будет парзить такую строку? :)
но, это еще не все!

на самом деле, в контексте мада, событий множество, все они дискретны, для каждого события должен быть отдельный вызов луа!!

поэтому, фактически, нельзя будет передать 1 гигантскую строку.
фактически, придется делать много вызовов. например, так:

Код:
for (int i = 1; i<10000; i++)
{
    sprintf(code, "
      foo = {}
      foo.Bar[%d] = %d
      foo.Bar[%d] = %d
      foo.Bar[%d] = %d
      foo.Bar[%d] = %d
      foo.Bar[%d] = %d
      --- ....
      foo.Bar[%d] = %d", i, foo.Bar[i], i+1, foo.Bar[i+1], i+2, foo.Bar[i+2], i+3, foo.Bar[i+3], ... i+9, foo.Bar[i+9]);

    luaL_dostring(luaState, code);
   
}

вот, теперь у нас еще вдобавок ко всему 10к вызовов.
и теперь это уже работает вообще страшно долго.

как раз чтобы таким образом не извращаться, для C API придумали функцию

lua_setfield

которая позволяет делать это всё быстрее
кароче идет работа напрямую с луа-стеком, минуя парзинг данных

и вот даже несмотря на все эти оптимизации, всё равно присваивание таблице 1 млн. значений, работает 7 секунд.

Автор:  Эрендир [ Сб ноя 20, 2010 2:31 am ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

я всё это как бы понимаю, хотя сам практически не занимался именно интеграцией Луа в Си.
Так вот, слегка порывшись по мануалам и прочим интернетам я родил следующий код:

Код:
#include <iostream>

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

void report_errors(lua_State *L, int status)
{
  if ( status!=0 ) {
    std::cerr << "-- " << lua_tostring(L, -1) << std::endl;
    lua_pop(L, 1); // remove error message
  }
}

int main(int argc, char** argv)
{
  for ( int n=1; n<argc; ++n ) {
    const char* file = argv[n];

  lua_State *L;
  L = L = luaL_newstate();
  luaL_openlibs(L);

  std::cerr << "-- Loading file: " << file << std::endl;
  int s = luaL_loadfile(L, file);
   
   
  lua_newtable(L);
  for (int i=0; i < 1000000; i++){
    lua_pushstring(L, "bar");
    lua_pushnumber(L, 10);
    lua_rawset(L, -3);
  }
  lua_setglobal(L, "foo");

  lua_newtable(L);
  for (int i=0; i < 1000000; i++){
    lua_pushnumber(L, i);
    lua_pushnumber(L, i*2);
    lua_rawset(L, -3);
  }
  lua_setglobal(L, "t");


    if ( s==0 ) {
      // execute Lua program
      s = lua_pcall(L, 0, LUA_MULTRET, 0);
    }

    report_errors(L, s);
    lua_close(L);
    std::cerr << std::endl;
  }

  return 0;
}

компилировать так:
Код:
g++ test.cpp -o test -pedantic -Os -Ipath/to/Lua/include/ -Lpath/to/Lua/lib/ -llua5.1


теперь нужен ещё test.lua:
Код:
print(foo)
print(foo.bar)
print(t)
print(t[1],t[999999])


запускать так:
Код:
test test.lua

выполнение кода длится 0.333 секунды, и это включая парсинг и компиляцию скрипта test.lua.
(незначительного прироста производительности можно добится использованием `lua_createtable(L,1000000,0);` для второй таблицы)

При всё при этом сначала 10^6 раз выполняется код из Вашей статьи (`Measure("LuaDLL.lua_settable", 1000000, () =>`), а потом ещё заполняется миллион разных полей для новой таблицы.

Что возвращает нас к моему утверждению: ни Луа, ни Lua C API не виноваты в том, что Ваша программа работает очень медленно.

Автор:  omlin [ Сб ноя 20, 2010 4:22 am ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

вынужден признать, дело было, по всей видимости, действительно не в бобине (не в парзинге).
на самом деле спасибо большое, что открыли глаза на это заблуждение.

но проблемы с производительностью всё равно имеются.

я подготовил вот такой код (на основе Вашего):

Код:
#include <iostream>
#include <ctime>

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

int main(int argc, char** argv)
{

   lua_State *L;
   L = L = luaL_newstate();

   char s[255];

   lua_newtable(L);

   clock_t t0 = clock();
   for (int i=0; i < 1000000; i++){
      // тут тестим
   }

   clock_t t1 = clock();
   std::cout << "time: " << (double)(t1 - t0) / CLOCKS_PER_SEC << std::endl;

   lua_close(L);

}


вместо "// тут тестим", вписываю, последовательно, следующие вещи:

Код:
sprintf(s, "bar%d", i);
lua_pushstring(L, s);
lua_pushnumber(L, i*3);
lua_settable(L, -3);

time: 6.343

Опа! 6 секунд всплыло...
Но может, это sprintf?
Проверим:

Код:
sprintf(s, "bar%d", i);

time: 1.813

sprintf, да не совсем. 4.5 секунды остаётся на луа...
А ведь при этом, вариант:

Код:
lua_pushstring(L, "bar");
lua_pushnumber(L, i*3);
lua_settable(L, -3);

time: 0.265

работает очень быстро.
также быстро работает и вот такой вариант:

Код:
lua_pushnumber(L, i);
lua_pushnumber(L, i*3);
lua_settable(L, -3);

time: 0.281

, НО!!

Код:
lua_pushnumber(L, i*2);
lua_pushnumber(L, i);
lua_settable(L, -3);

time: 1.39

и еще:

Код:
lua_pushnumber(L, 1000000-i);
lua_pushnumber(L, i*3);
lua_settable(L, -3);

time: 0.968

Интересные, в целом, результаты.
К сожалению, нет особо времени смотреть, что там в луа происходит, но видимо какой то кэш или хэш у них там есть, на обращение к филду...

Это, на самом деле, очень хорошо, думаю, многие проблемы с производительностью можно решить, если держать пару глобальных переменных постоянно в стеке (типов монстр, предмет, и т.п.), и в дальнейшем использовать для передачи данных именно их, а не вновь создаваемые таблицы.

Резюмируя
Эрендир в конечном итоге оказался прав.
Пожалуй, проблемы с производительностью в луа не критичны даже для реализации выносных скиллов/спеллов.

Автор:  Эрендир [ Сб ноя 20, 2010 4:57 am ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

Рад, что мне удалось Вас убедить!

И теперь уже видимо [offtop]:
первый пример (`sprintf(s, "bar%d", i);`) можно ускорить примерно вдвое, если вместо lua_newtable(L); использовать lua_createtable(L,0,1000000);
также он естественно самый медленный: сначала в куче создаётся миллион строк вида "bar%d", а потом наша тестовая таблица последовательно раздувается (пересчитывается non-array часть) во время заполнения (это можно избежать с lua_createtable )
пример с заполнением каждого второго (i*2) индекса можно ускорить либо за счёт (временного) места (lua_createtable(L,2000000,0);) (и потом задержка на итерации GC), либо посчитать руками, какого размера array часть, и какого non-array будет у такой таблицы.
пример с заполнением с конца (1000000-i) ускоряется аналогично.
[/offtop]

[offtop]
И да, я сам не был уверен в результатах, пока не занялся тестами, и, признаться, увидев Ваш пост про 7 секунд поначалу испугался: я всё лелею мечту понемножечку доклепать движок на чистом Луа (+luasocket и т.п., ессно), и если бы он тормозил даже с 10 игроками, это было бы ну очень обидно ;)
[/offtop]

Автор:  Харч [ Сб ноя 20, 2010 9:31 am ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

Извините, я, как новичок в создании мадов, не знаю, Lua - специальный язык написанный для скриптинга мадов?

Автор:  Эрендир [ Сб ноя 20, 2010 6:17 pm ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

http://www.google.com/search?q=lua

Автор:  omlin [ Вс ноя 21, 2010 12:45 am ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

LUA - это один из популярнейших встраиваемых языков для игр. Используется, в частности, в WOW.
Встраиваемый язык означает, что вы можете использовать луа в качестве языка для триггеров, или других нужд, предполагающих необходимость создания скриптов.

Эрендир писал(а):
первый пример (`sprintf(s, "bar%d", i);`) можно ускорить примерно вдвое, если вместо lua_newtable(L);...

Первый пример наиболее близок к реальности из всех перечисленных, однако, как я уже упоминал, всё-таки в реальности скорее будет что-нибудь типа 5к созданий таблицы с 20 полями. Всё-таки, один объект с 1 млн. полей это абстракция.
Так что выигрыша в производительности тут врядли удастся добиться именно с помощью lua_createtable.

Нет, тут надо по-другому действовать.
Объекты передаются строго определенных типов.
В частности, это мобы, комнаты, и предметы.
Причем, за один раз таблиц каждого вида может передаваться, наверное, не больше трех.
Например, FIGHT-триггер требует self и actor, оба типа "монстр".
С другой стороны, после отрабатывания триггера эти переменные становятся ненужными, а значит, их можно либо совсем удалить из кучи, либо использовать повторно.

Если заранее создать по 3 таблицы каждого возможного типа, сохранить их в некоторых глобальных переменных, и затем, при передаче данных использовать именно эти таблицы, то скорость работы, по всей видимости, должна увеличиться в сотни раз.

Эрендир писал(а):
я всё лелею мечту понемножечку доклепать движок на чистом Луа (+luasocket и т.п., ессно)

Может быть, это и реально, но очень напоминает забивание гвоздей микроскопом - только потому, что микроскоп нравится и с ним привычнее работать:)

Ну в самом деле, язык должен выбираться под нужды. Потому что язык - это инструмент. Хороший, подходящий инструмент увеличивает скорость работы, и качество работы, в разы и даже на порядки.

Ну банальный пример, в луа нет настоящего ООП, это не критично для скриптов, но это критично для большого проекта.
Наследование, инкапсуляция, полиморфизм - всё это помогает и в том, чтобы создать гибкий и легко расширяемый проект.
Строгая типизация (как в С++, С# и java) позволяет отловить многие ошибки на стадии компиляции. На самом деле компиляция - это первый юнит-тест! В луа с типизацией всё намного проще, хотя луа конечно получше в этом плане, чем, к примеру, перл.
Подготовленные и проверенные механизмы для юнит-тестов, руководства, мануалы, библиотеки, комьюнити - во всем этом С++, java и С# тоже выигрывают.
Ну и всякий синтаксический сахар, как например, Linq, Generic'и, перегрузка операторов...

Подумай:) Мад на луа это ж ведь как раз тот самый велосипед с квадратными колесами, который делает сейчас Харч, только в добавок ко всему ты лелеешь этот велосипед собрать при помощи микроскопа :)

Ребяты! Если вам интересно работать над мадом, если у вас есть светлая голова, давайте объединяться.
Да, при этом придется идти на уступки, учиться работать в команде, иногда - делать вещи, которые делать не очень хочется.
Но это полезные навыки, и на работе, и в семейной жизни, и вообще в жизни.

И главное, ведь есть совершенно реальный шанс прочувствовать и увидеть, что результат вашей работы оценен, используется и нравится конечным пользователям...

Автор:  Эрендир [ Вс ноя 21, 2010 1:21 am ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

Не буду спорить про микроскоп и прочие юнит-тесты... Поживём-увидим, как говорится. Или не увидим, если я и дальше буду лениться. :)

Одно замечание: Луа не акроним. Писать ЛУА неправильно. Луа означает Луна (по-португальски, емнип).

По-поводу комманды: опыт объединения исключительно через интернет, без каких-либо других объединяющих факторов лично у меня отрицательный. Причём, емнип, дважды. Правда и я тогда был помладше и глупее, но всё же настроение относительно таких команд скептическое.

Автор:  omlin [ Вс ноя 21, 2010 1:47 am ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

Однако же, если программист, то всё равно куда от команды? Разве что в суппорт на какое нибудь производство, а это буэ страшное, лучше даже не соваться. Убивает мозги за полгода, гарантированно. Я уж не говорю про сисадминство...

Самое классное это конечно тимлидом в стартапах. Но, опять же, тимлид => команда :)

Нет, если хочется программировать, от команды никуда. Я прошел весь этот путь, начинал в Хьерварде, потом писал собственный мад в одиночку, потом в малой команде, потом еще один проект мада писали - тоже с парой ребят, ну в итоге пришел в Адан...

Причем, Хьервард был как раз неприятным опытом. Полгода не было у меня возможности вылезать в мад, прихожу через полгода, и мне говорят что-то типа такого: у нас новый главбилдер (мой бывший билдер), пиши ему письмо, он посмотрит твою зону.

На самом деле, всё очень зависит от руководителя проекта.

Но если вы видите, что к примеру в былинах куча народу работает, ну ведь неспроста? Значит, лидер там, с большой вероятностью, умелый.

И кстати, после Хьерварда я пришел практически к таким же выводам, и начал писать сам.
Но две попытки подряд для меня оказались достаточными, чтобы понять, что создание полномасштабного мада, это задача не для одного человека. Даже если движок за год накатать, а мир кто делать будет? А редактор мира? А справку? А баланс? А сайт?...

Даже, на самом деле, не для двух человек. И еще нельзя забывать современные реалии, когда мады уже вышли из пика своей популярности, и чтобы в них играли, придется немало усилий приложить.

Нет, никуда без команды в мадах, никуда.

Автор:  Эрендир [ Вс ноя 21, 2010 2:34 am ]
Заголовок сообщения:  Re: mud design-concepts (расширяемость)

Цитата:
Однако же, если программист, то всё равно куда от команды?

а я не програмист ;)

Но опять же, я не против команды вообще, я против команды, собранной исключительно через интернет, т.к. опыт такого рода у меня печальный. Я рискну предположить, что в Былинах работает куча людей, потому что есть некое ядро, несколько человек, знакомых друг с другом в реале, условно "вокруг которых" держаться остальные члены команды.
Цитата:
понять, что создание полномасштабного мада, это задача не для одного человека.

О, я прекрасно отдаю себе в этом отчёт, и мой план примерно таков:
1. Сделать движок, минимальный кусочек мира, более-менее сбалансированную механику,справку на всё что есть.
2. Порекламировать такой набросок, позвать желающих в билдеры
3. ??????
4. PROFIT!!!

(самое сложное тут, несомненно, пункт 4 ;))

Пока же я нахожусь где-то в начале очередной итерации номера 1, части а: движок :)

Страница 2 из 3 Часовой пояс: UTC + 3 часа [ Летнее время ]
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/