eu_tomat 2 148 Опубликовано: 12 декабря, 2020 32 минуты назад, serafim сказал: Синхронизировать двух роботов на одну задачу оказалось не так просто как думалось, перепробовал пол сотни вариантов пока получилось хоть что-то не сильно лагучее Два робота совместно ставят и рубят один и тот же блок получая ускорение А в чём заключается преимущество именно такой схемы параллельной работы? Какой смысл размещать независимых роботов так, чтобы они имели общий блок для переработки руды, если проще сделать эти блоки отдельными для каждого робота? Это позволило бы вообще не задумываться о синхронизации роботов Мне было понятно, когда один робот рубил руду, а второй робот её устанавливал. Это позволяло повысить эффективность использования дорогого инструмента. Развивая эту идею, я использовал третьего и даже четвертого робота: три робота устанавливали руду в один общий блок, а четвёртый рубил руду в этом блоке. Но что даёт этот трюк с общим блоком в схеме на двух независимых роботах, когда каждый из них рубит своим инструментом? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
serafim 271 Опубликовано: 12 декабря, 2020 (изменено) 9 минут назад, eu_tomat сказал: А в чём заключается преимущество именно такой схемы параллельной работы? Идея в том чтоб не заморачиваться с ПО, роботы сами будут ставить или рубить руду в зависимости от того кто раньше успеет 9 минут назад, eu_tomat сказал: три робота устанавливали руду в один общий блок, а четвёртый рубил руду в этом блоке. Такой способ тоже хорош и экономный в плане инструмента и зарядчика 9 минут назад, eu_tomat сказал: что даёт этот трюк с общим блоком в схеме на двух независимых роботах, когда каждый из них рубит своим инструментом? Тут прироста увы нет, в основном влияет только время установки блока Изменено 12 декабря, 2020 пользователем serafim Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
eu_tomat 2 148 Опубликовано: 12 декабря, 2020 @serafim Что-то я запутался. 36 минут назад, serafim сказал: Идея в том чтоб не заморачиваться с ПО, роботы сами будут ставить или рубить руду в зависимости от того кто раньше успеет Это понятно. Но если вдобавок к этому мы разместим роботов так, чтобы каждый из них рубил в своём блоке, то о синхронизации вообще не надо будет думать. Каков смысл общего блока для совместной работы двух роботов, если у каждого есть свой инструмент для рубки? 40 минут назад, serafim сказал: Такой способ тоже хорош и экономный в плане инструмента и зарядчика Какой способ хорош? Мой с тремя установщиками и одним рубщиком? Или тот, который предложил ты с двумя роботами? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
serafim 271 Опубликовано: 12 декабря, 2020 (изменено) 22 минуты назад, eu_tomat сказал: Каков смысл общего блока для совместной работы двух роботов, если у каждого есть свой инструмент для рубки? это тайна покрытая мраком, а вообще надежда на рассинхрон вычислений сервера с клиентом позволяющий моментально сносить блоки 22 минуты назад, eu_tomat сказал: Какой способ хорош? Мой с тремя установщиками и одним рубщиком? Твой, но увы тут ПО писать особо не о чем Изменено 12 декабря, 2020 пользователем serafim Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
eu_tomat 2 148 Опубликовано: 12 декабря, 2020 @serafim Ну, ясно. Нет особого смысла направлять роботов в один блок, если речь не идёт об экономии на дорогом инструменте. Теперь вернёмся к теме заказа. Меня эта задачка заинтересовала своей экстремальностью, поэтому я потратил много времени на исследование способов, позволяющих достичь максимальной скорости переработки руды. Мы с автором заказа обсуждали в дискорде возможные варианты, но он отверг все предложенные мной улучшения схемы. Он сопротивляется каким-либо изменениям изначальной схемы и разрешает только оптимизировать код программ. При таких условиях для меня это совершенно неинтересная задача с точки зрения кодинга. Но благодаря примитивности эти двух программ я считаю их хорошими примерами для оптимизации. Если я и перепишу эти две программы, то это будет в формате блога с раскрытием темы оптимизации. Если же тебе интересна задача, ты можешь сделать это раньше меня и без лишних слов, аккуратно с нуля написав обе программы, не используя лишних операций или заменив медленные операции более быстрыми. Также мы можем совместно работать над новым вариантом, если тебе интересен такой формат: ты пишешь код, а я анализирую его эффективность. В этом случае мы с тобой сможем раскрыть тему оптимизации последовательно, пост за постом. Какой из вариантов работы над этим заказом тебе наиболее интересен? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
serafim 271 Опубликовано: 13 декабря, 2020 17 часов назад, eu_tomat сказал: мы можем совместно работать над новым вариантом ... В этом случае мы с тобой сможем раскрыть тему оптимизации последовательно, пост за постом. идея интересная Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
eu_tomat 2 148 Опубликовано: 13 декабря, 2020 1 час назад, serafim сказал: идея интересная Начнём с установщика блоков: Скрытый текст local sides = require "sides" local robot = require "robot" local component = require "component" local active_slot = 1 size=robot.inventorySize() local function Text() os.execute("cls") print("РОБОТ РАБОТАЕТ!! Создатель - GooodGame") print("Доработал-atomzerg") end Text() while true do robot.select(active_slot) if robot.count(active_slot) == 0 then active_slot = active_slot + 1 end if robot.select(active_slot) ==size then active_slot = 1 end if robot.place() == false then active_slot = active_slot + 1 end if active_slot == size then active_slot = 1 end robot.place() end Предварительный, грубый анализ: Программа в основном расходует время на выполнение бесконечного цикла. Внутри бесконечного цикла безусловно выполняются следующие операции: Два раза выполняется robot.select, затрачивая 0.05 сек на вызов. Один раз robot.place, затрачивая 0.4 сек на вызов Один раз robot.count, на вызов тратится примерно 5E-5 сек времени. Успешные вызовы robot.place приближают игрока к цели, нет смысла уменьшать количество этих вызовов, но есть смысл подготовить робота таким образом, чтобы каждый вызов был успешным, т.к. выполнение неудачного вызова требует 0.05 сек времени. Программа проверяет успешность операции кодом: if robot.place() == false, но из этого делается неверный вывод, будто бы закончились предметы в слоте. Это не верно. Такое условие сообщает о том, что не удалось установить блок в мир: скорее всего, есть какая-то помеха. Для проверки наличия предмета в слоте могло бы подойти условие if robot.place() == nil, но эту проверку можно гораздо быстрее осуществить с помощью robot.count(). В случае же, если не удалось установить блок, имеющийся в слоте робота, требуется просто подождать, пока освободится пространство в координатах установки. Также неудача при установке блока возможна в случае, когда в инвентарь робота попал предмет, не являющийся блоком. Но это уже проблема корректности настройки фильтров в логистических сетях на базе игрока. Думаю, этот вариант вообще не имеет смысла анализировать в программе. Вызовы robot.select() приближают игрока к цели только в том случае, если текущий слот инвентаря опустел. И при достаточно быстром заполнении инвентаря робота блоками руды требуется не более 1/64 этой операции на одну итерации цикла. Минимизируя количество вызовов этой операции удастся сэкономить 0.05*2 - 0.05/64 секунд на одну итерации цикла. Относительно времени, затраченного на основную операцию, экономия составит 19.84%. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
eu_tomat 2 148 Опубликовано: 13 декабря, 2020 Для информации, чтобы читателям было понятно, что здесь происходит: @serafim выложил свои варианты программ, но пока решил притормозить, чтобы не участвовать в создании лагодромов. Его позиция понятна, темы автора заказа вызывают противоречивые чувства. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
serafim 271 Опубликовано: 14 декабря, 2020 (изменено) Начнём пожалуй с самого начала, для оптимизации программы разберём предложенный код поэтапно Скрытый текст local sides = require "sides" local robot = require "robot" local component = require "component" local active_slot = 1 size=robot.inventorySize() local function Text() os.execute("cls") print("РОБОТ РАБОТАЕТ!! Создатель - GooodGame") print("Доработал-atomzerg") end Text() while true do robot.select(active_slot) if robot.count(active_slot) == 0 then active_slot = active_slot + 1 end if robot.select(active_slot) ==size then active_slot = 1 end if robot.place() == false then active_slot = active_slot + 1 end if active_slot == size then active_slot = 1 end robot.place() end 1 local sides = require "sides" библиотека sides на 1й строке - этот интерфейс предоставляет таблицу названий, для работы со сторонами блоков в формате: Низ (bottom): 0 , Верх (top): 1 , Тыл (back): 2 , Перед (front): 3 , Право (right): 4 , Лево (left): 5 пример для работы с контроллером красного камня: 1 local component = require("component") 2 local sides = require("sides") 3 local rs = component.redstone 4 rs.setOutput(sides.left,15) здесь использован rs.setOutput(sides.left,15) на 4й строке (включить сигнал с лева, с силой сигнала 15), без библиотеки sides пришлось бы указать сторону в формате rs.setOutput(5,15) Вот только в коде эта библиотека не используется, вызывать её не требуется 3 local component = require "component" библиотека component на 3й строке - этот интерфейс используется для доступа и взаимодействия компьютера с компонентами тот же пример для работы с контроллером красного камня: 1 local component = require("component") 2 local rs = component.redstone для того чтоб взаимодействовать с контроллером красного камня необходимо его назначить компонентом 2 local rs = component.redstone Вот только ни какие взаимодействия с компонентами в коде не происходят, вызывать её не требуется 5 size=robot.inventorySize() глобальная переменная size на 5й строке вызывается один раз при запуске программы и принимает значение последнего слота в инвентаре робота, который при одном улучшении инвентаря равен 16 ячейкам желательно назначать переменные локально 5 local size = robot.inventorySize() чтобы она не вносила изменения в другие программы за пределами данного кода 6 local function Text() 7 os.execute("cls") 8 print("РОБОТ РАБОТАЕТ!! Создатель - GooodGame") 9 print("Доработал-atomzerg") 10 end 12 Text() функция Text() вызывается только один раз на строке 12, её можно упростить 7 os.execute("cls") 8 print("РОБОТ РАБОТАЕТ!! Создатель - GooodGame") 9 print("Доработал-atomzerg") также вопрос а требуется ли она вообще, достаточно указать что за программа сейчас работает print("работает установщик блоков") теперь касательно основного тела программы: 16 robot.select(active_slot) 17 if robot.count(active_slot) == 0 then 18 active_slot = active_slot + 1 end 19 if robot.select(active_slot) ==size then 20 active_slot = 1 end 21 if robot.place() == false then active_slot = active_slot + 1 end 22 if active_slot == size then active_slot = 1 end 23 robot.place() текущий алгоритм работы: строка 16 выбирается активный слот инвентаря робота из переменной active_slot , при первом запуске она равна 1 строка 17 проверяется значение слота (в данном случае 1) и если он пустой то строка 18 к глобальной переменной active_slot плюсуется 1 строка 19 если выбран последний слот инвентаря робота то строка 20 переменная active_slot меняет значение на 1 строка 21 если робот не смог поставить блок то к активному слоту плюсуется 1 строка 22 если переменная active_slot равна последнему слоту робота то переменная active_slot меняет значение на 1 строка 23 робот ставит блок без проверок успешно или нет Вывод: в текущем алгоритме творится каша использован не оптимальный метод выбора заполненного слота назначая переменную active_slot если робот не может поставить блок то назначается следующий слот инвентаря независимо от того если там руда или нет, причиной не возможности поставить блок может быть из за того что блок ещё не сломали, или другой робот установщик поставил его раньше, в итоге будет постоянно перебирается инвентарь тратя время в пустую отдельно хотелось бы обратить внимание на форматирование кода, читать его затруднительно общепринято использовать для lua два пробела, да это не обязательно но сильно улучшает восприятия написанного кода второе - это как написаны логические элементы, тут не выделены начало и конец а также выполняемые условия каждое условие проверяется отдельно, хотя логичное было бы остановится на том которое соответствует требованию вот так должен был выглядеть код при соблюдении общепринятых норм while true do robot.select(active_slot) if robot.count(active_slot) == 0 then active_slot = active_slot + 1 elseif robot.select(active_slot) == size then active_slot = 1 elseif robot.place() == false then active_slot = active_slot + 1 elseif active_slot == size then active_slot = 1 end robot.place() end Использовать кучу условий и метод счётчика для выбора заполненного слота в инвентаре робота не эффективно правильнее применить цикл перебора инвентаря пропуская пустые слоты и при нахождении полного слота выбрать его, остановив дальнейший перебор for slot = 1, inv do if r.count(slot) > 0 then r.select(slot) break end end вместо кучи условий с переменной active_slot можно использовать только одно условие, (если выбранный слот пуст) if r.count() == 0 then также если инвентарь робота пустой, то не логично перебирать его до посинения, правильнее остановить поиск, пока в инвентаре не появится новые блоки, и при добавлении новых блоков, сразу его выбрать if slot == inv then local e, slot = event.pull("inventory_changed") r.select(slot) end проверять поставил ли робот блок нет необходимости if robot.place() == false then особенно если использованы несколько установщиков блоков, программа будет простаивать r.place() Собственно готовый код занимает всего 21 строку, осталось его только собрать до кучи Но я этого делать не буду, и вот почему: Эта программа при лагающем сервере вызывает рассинхрон при быстрой смене блока, устанавливая и разрушая его сервер выдаёт финты типа моментального разрушения или дюпа Подобные действия не способствуют популезации мода OpenComputers Рекомендую проголосовать за удалении этой темы как потенциально нежелательной Изменено 14 декабря, 2020 пользователем serafim 1 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
hohserg 195 Опубликовано: 14 декабря, 2020 1 час назад, serafim сказал: Рекомендую проголосовать за удалении этой темы как потенциально нежелательной Рекомендую заархивировать ее как пример потенциально нежелательной 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
eu_tomat 2 148 Опубликовано: 14 декабря, 2020 @serafim Хороший анализ плохого кода, я согласен почти с каждым утверждением. Но в удалении этой темы я не вижу смысла. В ней разобраны альтернативные варианты решения поставленной задачи, более экономно расходующие ресурсы сервера. Обсуждение проблемы лагодромов я считаю полезным. Большинство игроков создаёт лагодромы ненамеренно, т.к. попросту не знает, как писать программы правильно, как минимизировать нагрузку на сервер. Таким игрокам будет полезна информация о том, как решить задачу правильно. А тот, кто вредит серверу целенаправленно, готов использовать для этого любые другие моды, а не только OC. И останавливает такого игрока только одно средство — бан. Конечно же, не стоит выкладывать готовые скрипты для причинения вреда серверу. Но также не стоит и препятствовать обсуждению плохо спроектированного кода из опасений, что оно будет содержать намёки на возможность создания явно вредоносных программ. Под этим предлогом можно было бы удалить многие темы нашего форума. Но что нам это даст? 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
serafim 271 Опубликовано: 14 декабря, 2020 (изменено) 14 минуты назад, eu_tomat сказал: Под этим предлогом можно было бы удалить многие темы нашего форума может и так, тогда предлагаю отправить данную тему в корзину там можно будет её смотреть, но нельзя редактировать либо добавить на сайт новую ветку лагодромы рядом с корзиной, закрытую от редакции Изменено 14 декабря, 2020 пользователем serafim Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
eu_tomat 2 148 Опубликовано: 21 декабря, 2020 В 14.12.2020 в 16:31, serafim сказал: также если инвентарь робота пустой, то не логично перебирать его до посинения, правильнее остановить поиск, пока в инвентаре не появится новые блоки, и при добавлении новых блоков, сразу его выбрать if slot == inv then local e, slot = event.pull("inventory_changed") r.select(slot) end Тут ещё не помешает проверка на наличие предмета в слоте, т.к. по завершении обработки 64 блоков руды очередь гарантированно забьётся событиями извлечения предмета из слота, из-за чего с большим шансом слоты, на которые указали сигналы, могут оказаться пустыми. Кстати, очень странно, что событие inventory_changed вообще генерируется при установке блока. Причём, аж 4 раза . Не должно быть ни того, ни другого. Оно должно вызваться один раз при исчерпании стака, как при выбрасывании предметов по одной штуке. Проверялось для OpenComputers-MC1.7.10-1.7.5.1290-universal.jar. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
serafim 271 Опубликовано: 21 декабря, 2020 1 час назад, eu_tomat сказал: очень странно, что событие inventory_changed вообще генерируется при установке блока. Событие "key_down" также временами срабатывает без нажатия кнопок, приходится дополнительно его проверять. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
eu_tomat 2 148 Опубликовано: 21 декабря, 2020 2 минуты назад, serafim сказал: Событие "key_down" также временами срабатывает без нажатия кнопок, приходится дополнительно его проверять. А при каких условиях оно генерируется кроме, собственно, нажатия кнопок? 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
serafim 271 Опубликовано: 21 декабря, 2020 Только что, eu_tomat сказал: А при каких условиях оно генерируется кроме, собственно, нажатия кнопок? не известно, но кнопок никто не нажимает, но событие происходит Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
eu_tomat 2 148 Опубликовано: 21 декабря, 2020 Только что, serafim сказал: не известно, но кнопок никто не нажимает, но событие происходит Можешь скинуть пример кода для демонстрации этого эффекта? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
serafim 271 Опубликовано: 21 декабря, 2020 1 минуту назад, eu_tomat сказал: Можешь скинуть пример кода для демонстрации этого эффекта? Происходит это при работе карьера, но не всегда. В ранних версиях использовал код такого вида: Скрытый текст local e = {require("event").pull("key_down")} if e[4] == 49 then print("программа завершена") os.exit() elseif e[1] == "key_down" then print("нажата кнопка") end Робот возвращался к старту, и по событию key_down должен был продолжить копать, но в итоге он приезжал и сразу ехал обратно Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
eu_tomat 2 148 Опубликовано: 21 декабря, 2020 3 минуты назад, serafim сказал: Происходит это при работе карьера, но не всегда. То есть, это какой-то трудновоспроизводимый глюк? Это проверялось в сигнле или на сервере? Другие игроки могли внести изменения в BIOS или библиотеки? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
serafim 271 Опубликовано: 21 декабря, 2020 Только что, eu_tomat сказал: это какой-то трудновоспроизводимый глюк? Это проверялось в сигнле или на сервере? по видимому глюк в сингле Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах