nerevar / jmc

JMC - Jaba Mud Client
26 stars 14 forks source link

Бесконечный цикл #51

Open Rorifer opened 8 years ago

Rorifer commented 8 years ago

При формировании бесконечного цикла команд - жабу крешит при накоплении како-то буфера.. т.е. набор тригеров:

var tick1 0

ali {тест1}{#out $tick1;#math {tick1}{$tick1+1};тест2}

ali {тест2}{#out $tick1;#math {tick1}{$tick1+1};тест1}

крешит 3.6.1.1 при 53 операциях. 3.0.5 при 32 операции. 3.26 при 80 операциях А теперь вопрос =) можно как то увеличить буфер? Креш я так понимаю из за переполнения очереди команд происходит ведь?

konelav commented 8 years ago

Формально это называется косвенная хвостовая рекурсия. Более простой (не косвенный) вариант той же ситуации: #ali {тест} {#out $tick;#math tick {$tick+1};тест} тест В случае жабы это транслируется в чистом виде в рекурсивные вызовы parse_input(...) в ядре TinTin.

Проблема рекурсии в том, что она жрёт стек, а это не совсем обычный "буффер". Его можно увеличить, но необходимость этого, как правило, свидетельствует о неправильно выбранных алгоритмах в принципе, и в данном случае приведет к увеличению возможной глубины вызовов максимум на порядок, что как-то грустно всё равно. Ведь, например, хвостовая рекурсия однозначно сворачивается в цикл и, соответственно, жрать стек перестаёт вовсе. Также целесообразней TinTin'у самому управлять отдельным стеком под выполнение команд, выделять его динамически и не зависеть от "собственного" стека в этом плане.

Я набросал предварительный фикс, выполняющий в случае хвостовой и некоторых других видах рекурсии произвольное количество вызовов, а в остальных -- ограниченное выделяемой ОС памятью. Но это серьёзное изменение модели вычислений TinTin'а вообще, так что весьма вероятно, что что-то сломалось, хотя на моих конфигах всё ок. После выполнения некоторой оптимизации и всестороннего тестирования, если всё будет хорошо, я сделаю соответствующий пулл-реквест. Тут будет очень полезна реализация идеи Романа: нужен какой-то скрипт-файл (типа *.set-файлов), например selftest.set, такой, чтобы запустив из жабы #read selftest.set можно было относительно легко понять, нормально всё работает, или что-то сломалось. Мои собственные конфиги весьма скудны в плане set-файлов, так что не уверен, что смогу сделать достаточно всеобъемлющие тесты. Простое всякое -- легко, но извращения типа #var x #a;#var y {lias fo};#var z {o bar} $x$y$z вряд ли переберу, особенно со всякими вложенными if-ами с одноимёнными переменными.

Тут очень хочется напомнить Правило Гринспуна. Моё сугубо личное, но очень глубокое убеждение: не следует воспринимать TinTin как среду для сколь-нибудь серьезных вычислений; это должен быть простой как топор и надёжный доступ к примитивным и базовым вещам: подключение, горячие клавиши, логирование, прокси, сжатие, промпт... Смотрите сами: #if ущербен, #math убог, #action ограничен, притом всё это довольно сложные для понимания, плохо документированные и зачастую контринтуитивные конструкты (с этими их %%1, "}" и т.п.). Есть поддержка ActiveScript: это и javascript, и python, и lua, и кому что нравится вообще. Всё это отработанные во множестве областей десятками тысяч программистов и сотнями миллионов юзеров инструменты, многие идеально подходят для любых MUD-задач. Очень простые для изучения, со множеством примеров, широким комьюнити, понятными книгами для начинающих. И тут совершенно легко и естественно пишутся хоть БД предметов/мобов, хоть боты, хоть мапперы: для TinTin'а задачи совершенно неподъёмные.

Rorifer commented 8 years ago

Спасибо за столь развернутый ответ. Полностью согласен со всем сказанным. Тогда может как-то можно ограничить рекрсивную функцию, чтоб она хоть жабу не крешила... Что то типа при заполнении стека в 20 команд не ждать до 30 с последующим вылетом, а к примеру стопнуть все циклы, обнулить стек и вывести сообщение в мейн об ошибке? 16 марта 2016 г. 20:24 пользователь "konelav" notifications@github.com написал:

Формально это называется косвенная хвостовая рекурсия https://en.wikipedia.org/wiki/Tail_call. Более простой (не косвенный) вариант той же ситуации:

ali {тест} {#out $tick;#math tick ($tick+1};тест}

В случае жабы это транслируется в чистом виде в рекурсивные вызовы parse_input(...) в ядре TinTin.

Проблема рекурсии в том, что она жрёт стек, а это не совсем обычный "буффер". Его можно увеличить, но необходимость этого, как правило, свидетельствует о неправильно выбранных алгоритмах в принципе, и в данном случае приведет к увеличению возможной глубины вызовов максимум на порядок, что как-то грустно всё равно. Ведь, например, хвостовая рекурсия однозначно сворачивается в цикл и, соответственно, жрать стек перестаёт вовсе. Также целесообразней TinTin'у самому управлять отдельным стеком под выполнение команд, выделять его динамически и не зависеть от "собственного" стека в этом плане.

Я набросал предварительный фикс, выполняющий в случае хвостовой и некоторых других видах рекурсии произвольное количество вызовов, а в остальных -- ограниченное выделяемой ОС памятью. Но это серьёзное изменение модели вычислений TinTin'а вообще, так что весьма вероятно, что что-то сломалось, хотя на моих конфигах всё ок. После выполнения некоторой оптимизации и всестороннего тестирования, если всё будет хорошо, я сделаю соответствующий пулл-реквест. Тут будет очень полезна реализация идеи Романа https://github.com/nerevar/jmc/pull/46#issuecomment-182070905: нужен какой-то скрипт-файл (типа *.set-файлов), например selftest.set, такой, чтобы запустив из жабы #read selftest.set можно было относительно легко понять, нормально всё работает, или что-то сломалось. Мои собственные конфиги весьма скудны в плане set-файлов, так что не уверен, что смогу сделать достаточно всеобъемлющие тесты. Простое всякое -- легко, но извращения типа

var x #a;#var y {lias fo};#var z {o bar}

$x$y$z вряд ли переберу, особенно со всякими вложенными if-ами с одноимёнными переменными.

Тут очень хочется напомнить Правило Гринспуна https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule. Моё сугубо личное, но очень глубокое убеждение: не следует воспринимать TinTin как среду для сколь-нибудь серьезных вычислений; это должен быть простой как топор и надёжный доступ к примитивным и базовым вещам: подключение, горячие клавиши, логирование, прокси, сжатие, промпт... Смотрите сами: #if ущербен, #math убог, #action ограничен, притом всё это довольно сложные для понимания, плохо документированные и зачастую контринтуитивные конструкты (с этими их %%1, "}" и т.п.). Есть поддержка ActiveScript: это и javascript, и python, и lua, и кому что нравится вообще. Всё это отработанные во множестве областей десятками тысяч программистов и сотнями миллионов юзеров инструменты, многие идеально подходят для любых MUD-задач. Очень простые для изучения, со множеством примеров, широким комьюнити, понятными книгами для начинающих. И тут совершенно легко и естественно пишутся хоть БД предметов/мобов, хоть боты, хоть мапперы: для TinTin'а задачи совершенно неподъёмные.

— You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub https://github.com/nerevar/jmc/issues/51#issuecomment-197442171

nerevar commented 8 years ago

Да, конечно, это же рекурсия и её нужно ограничивать. Например, выполнять следующий шаг итерации, только, если $tick будет меньше какого-то значения, 30 например:

#ali {тест1}{#out $tick1;#math {tick1}{$tick1+1};#if {$tick < 30} {тест2}}
#ali {тест2}{#out $tick1;#math {tick1}{$tick1+1};#if {$tick < 30} {тест1}}
Rorifer commented 8 years ago

Роман, ограничение этого действия руками пользователя понятно. я говорю о защите от.. невнимательности в случае косвенной рекурсии 20 марта 2016 г. 23:31 пользователь "Roman Rybalchenko" < notifications@github.com> написал:

Да, конечно, это же рекурсия и её нужно ограничивать. Например, выполнять следующий шаг итерации, только, если $tick будет меньше какого-то значения, 30 например.

— You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub