Способы Повышения Производительности, методы оптимизации lua кода |
Здравствуйте, гость ( Вход | Регистрация )
Способы Повышения Производительности, методы оптимизации lua кода |
2.1.2012, 22:57
Сообщение
#21
|
|
KEEP CLEAR AT ALL TIMES Группа: Пользователи Сообщений: 141 Регистрация: 4.9.2011 Из: Беларусь, Минск Пользователь №: 9 667 Спасибо сказали: 3 раза |
Как вариант – использовать модуль, который будет следить за пользователями с "нужным(ми)" префиксами, а также учитывал статистически какие команды, сообщения (правильные или неправильные) вводятся... и, используя эти данные, выбирал (переключался на) наиболее оптимальный вариант поиска для всевозможных случаев (или, по крайней мере, учесть те случаи, которые возможны при использовании тех скриптов, которые уже есть) . А данные от этого модуля могли бы использовать все скрипты.
|
|
|
2.1.2012, 23:10
Сообщение
#22
|
|
Освоившийся участник Группа: Пользователи Сообщений: 391 Регистрация: 4.11.2009 Из: Дом Пользователь №: 4 923 Спасибо сказали: 239 раз |
А? Ты че-то не то пишешь. Или не туда. Тут речь о префиксах команд. Т. е. о наименее ресурсоёмком определение, что именно прислал пользователь - команду или текстовое сообщение в чат.
"!regme" - это команда "Привет всем!" - это сообщение. В первом случае скрипт должен отработать и что-то сделать, перехватив вывод команды в чат, а во-втором, пропустить сообщение в чат, ничего не выполняя, с наименьшими затратами ресурсов. ADD: Продолжая тему оптимизации. Тест Код: Код function ChatArrival(tUser, sData) local iPos = #tUser.sNick + 4 local iLimit = 10000000 local sChar = '!' local iChar = sChar:byte(1); local iCounter = 0; local iStart = os.time() iCounter = 0 for i = 0, iLimit, 1 do if sData:sub(iPos, iPos):find('!', 1, true) then iCounter = iCounter + 1 end end Core.SendToAll(iCounter .. " " .. os.difftime(os.time(), iStart)); iStart = os.time() iCounter = 0 for i = 0, iLimit, 1 do if sData:sub(iPos, iPos) == '!' then iCounter = iCounter + 1 end end Core.SendToAll(iCounter .. " " .. os.difftime(os.time(), iStart)); iStart = os.time() iCounter = 0 for i = 0, iLimit, 1 do if sData:byte(iPos) == iChar then iCounter = iCounter + 1 end end Core.SendToAll(iCounter .. " " .. os.difftime(os.time(), iStart)); end Результат: Код [22:18:22] *10000001 19 [22:18:22] *10000001 11 [22:18:22] *10000001 10 [22:18:22] 127.0.0.1 | ?? на хабе Находится <ВВВВВВВВВВВВВВВВВВВВ> !say test [22:19:11] *0 18 [22:19:11] *0 11 [22:19:11] *0 9 [22:19:11] 127.0.0.1 | ?? на хабе Находится <ВВВВВВВВВВВВВВВВВВВВ> test Вывод: Самый быстрый способ - использование byte, для получения кода конкретного символа. UPD: Исправил ошибку в коде. PS что интересно, так это четко видная буферизация вывода. В клиент все пришло одновременно, независимо от того, что отдельные строки отсылались с разрывом порядка 10 секунд. |
|
|
2.1.2012, 23:11
Сообщение
#23
|
|
KEEP CLEAR AT ALL TIMES Группа: Пользователи Сообщений: 141 Регистрация: 4.9.2011 Из: Беларусь, Минск Пользователь №: 9 667 Спасибо сказали: 3 раза |
Это с идеальной точки зрения...
Некоторые пишут: Цитата "Привет!" А некоторые: Цитата "!Всем привет!" "!С наступившим Новым 2012 Годом!" И так далее... надо и такое учитывать,) Enyby, Вы так "жёстко" определили где команда, а где сообщение. Это понятно, правильно. Но ведь есть разные случаи жизни, кто-то ошибается с вводом команды... и получается сообщение... по разным причинам. Или кто-то подбирает команды... а в результате могут получатся и команды, и сообщения. P.S.: Код [22:07:31] 127.0.0.1 | ?? на хабе Находится <ВВВВВВВВВВВВВВВВВВВВ> test Уточните, пожалуйста, что это? |
|
|
2.1.2012, 23:29
Сообщение
#24
|
|
Освоившийся участник Группа: Пользователи Сообщений: 391 Регистрация: 4.11.2009 Из: Дом Пользователь №: 4 923 Спасибо сказали: 239 раз |
Ну и что. На 10 млн проверок (!) нужно порядка 10 секунд, на не самой быстрой машине. Т. е. порядка 1 млн проверок в секунду. Это не существенно. У вас юзеров за спам забанит намного раньше.
ADD: Enyby, Вы так "жёстко" определили где команда, а где сообщение. Это понятно, правильно. Но ведь есть разные случаи жизни, кто-то ошибается с вводом команды... и получается сообщение... по разным причинам. Или кто-то подбирает команды... а в результате могут получатся и команды, и сообщения. А так и есть. Все варианты не предугадаешь. Так что и не стоит даже заморачиваться. Завтра кошка будет по клавиатуре бегать, так вы скрипт анти кошка писать будете? Код [22:07:31] 127.0.0.1 | ?? на хабе Находится <ВВВВВВВВВВВВВВВВВВВВ> test Уточните, пожалуйста, что это? Это вывод в ДС клиенте сообщения в чат. Временной штамп, ип, страна, локация/провайдер, ник и само сообщение. Чтоб было понятнее - запустите тестовый скрипт и отправьте сообщение. Правда хаб подвисает на время брожения в циклах. Так что это нормально. ADD: В общем стоит задача отсеять "возможно команды" от точно "не команд". Все что началось не с префикса - командой быть не может. А если есть префикс, то тогда нужно регулярку, захватывать текст и проверять что это, известная команда или отсебятина. В любом случае, это будет менее ресурсоёмко, чем проверка каждого сообщения регуляркой. |
|
|
14.3.2012, 19:07
Сообщение
#25
|
|
Активный участник Группа: Пользователи Сообщений: 94 Регистрация: 2.10.2010 Из: Якутия, г.Нерюнгри Пользователь №: 7 820 Спасибо сказали: 21 раз |
И так далее... надо и такое учитывать,)
Ну так после отсеивания возможной команды следует проверка на саму команду. Так что если там и кошка пробежала то ничего страшного, выведется в чат как сообщение! А уж если команда то тогда уж и действие и return true скрипту в руки! Всё выше описанное участниками форума делается примерно так Код function ChatArrival(tUser, sData)
local iPos = #tUser.sNick + 4 if sData:sub(iPos, iPos):find('!', 1, true) then --поиск префикса команды -- дальнейшие действия (в том числе поиск и сравнение команд) local cmd = sData:sub(iPos+1,-2):match"(%S+)" --забираем то что после префикса if cmd == "команда" then -- Вот и само сравнение команды --Действие Core.SendToAll("<"..tUser.sNick.."> ".."Скрипт работает!") --Например так! return true --Не даём команде попасть в чат. end end end |
|
|
12.3.2013, 4:53
Сообщение
#26
|
|
Местный Группа: Неактивированные Сообщений: 908 Регистрация: 26.12.2008 Пользователь №: 1 574 Спасибо сказали: 1406 раз |
А вот небольшое замечание, касающееся хаба PtokaX.
Как известно, скриптовые функции, отправляющие данные юзерам (Core.SendToAll, Core.SendToUser, и.т.д.) не требуют наличия в конце строки символа |, и, при необходимости, добавляют его сами. Удобно, не спорю. Но давайте заглянем в исходный код: Код if(sData[szLen-1] != '|') { memcpy(g_sBuffer, sData, szLen); g_sBuffer[szLen] = '|'; g_sBuffer[szLen+1] = '\0'; UserSendCharDelayed(u, g_sBuffer, szLen+1); } else { UserSendCharDelayed(u, sData, szLen); } На этом куске функции Core.SendToUser нам вырисовывается такая картина маслом: если функция получила строку, завершающуюся символом |, она просто отправляет данные юзеру, ну а если символа | в конце нет, то вся строка копируется в буфер, затем к ней добавляется | и завершающий нулевой байт, и только после этого она отсылается юзеру. Вывод достаточно прост: если при отправке данных из скриптов вы будете сами добавлять | в конце, эти скрипты будут работать чуток быстрее. |
|
|
12.3.2013, 7:23
Сообщение
#27
|
|
Местная ТехПоддержка Группа: Администраторы Сообщений: 1 875 Регистрация: 18.7.2008 Из: Моск. Обл, г. королев, район Болшево Пользователь №: 221 Спасибо сказали: 220 раз |
Тут должен был быть пост с вопросом : "зачем пепяке с++ при таком коде?" Но его тут не будет.
|
|
|
12.3.2013, 15:26
Сообщение
#28
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Это не единственный грабли. Если присмотреться к исходникам, то там их можно очень много найти. Я уже не говорю о "макаронности" кода.
По всей видимости у них действует правило: "Работает - не трогай!", и поэтому рефакторинг кода никогда не делается. |
|
|
24.3.2013, 19:17
Сообщение
#29
|
|
KEEP CLEAR AT ALL TIMES Группа: Пользователи Сообщений: 141 Регистрация: 4.9.2011 Из: Беларусь, Минск Пользователь №: 9 667 Спасибо сказали: 3 раза |
Прочитав критическое замечание (Сообщение #26) от alex82 и будучи новичком в С++, все же задам вопрос: а какие варианты решения возможны в данном случае?
Предположу, что автор Птоки таким образом обходит всевозможные варианты ошибок, связанные с некорректным завершением отсылаемых команд/сообщений, т.е. в конце всегда должен быть символ "|". P.S.: читая со стороны одну лишь критику, для непосвящённого довольно сложно почерпнуть что-то полезное. |
|
|
24.3.2013, 21:10
Сообщение
#30
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
проблема не в символе, а в лишнем копировании данных
не смотрел реализацию функции UserSendCharDelayed, но возможно стоило написать так: Код UserSendCharDelayed(u, sData, szLen);
if(sData[szLen-1] != '|') { UserSendCharDelayed(u, "|", 1); } |
|
|
29.3.2013, 18:15
Сообщение
#31
|
|
7 квадратиков Группа: Модераторы Сообщений: 793 Регистрация: 21.1.2009 Пользователь №: 1 895 Спасибо сказали: 301 раз |
Вывод достаточно прост: если при отправке данных из скриптов вы будете сами добавлять | в конце, эти скрипты будут работать чуток быстрее. Вот что по поводу этого совета говорит PPK: Раскрывающийся текст Цитата(PPK) [05:17] <PPK> he is wrong [05:17] <PPK> adding pipe in lua is slower that when ptokax add it [05:19] <PPK> example: sMsg = "This is a test" slow way -> Core.SendToAll((2, sMsg.."|") fast way -> Core.SendToAll((2, sMsg) [15:27:31] <PPK> function OnStartup() starttime = os.time() Core.SendToAll("Start: "..tostring(starttime)) sMsg = "This is a test" for i = 1, 20000000 do Core.SendToProfile(2, sMsg.."|") end endtime = os.time() Core.SendToAll("End: "..tostring(endtime)) Core.SendToAll("Diff: "..tostring(endtime-starttime)) end [15:27:57] <PPK> x64 ptokax + 4 GB memory (result of this script is memory usage close to 4 GB) [15:28:07] <PPK> first test was with sMsg = "This is a test|" [15:28:19] <PPK> that should be fastest -> taken 12 second [15:28:30] <PPK> second test was with sMsg = "This is a test" [15:28:49] <PPK> that should be slower, but again take only 12 second [15:29:19] <PPK> and thirt test was with sMsg = "This is a test" and Core.SendToProfile(2, sMsg.."|") (previous two without adding pipe here) [15:29:23] <PPK> and this one take 16 seconds [15:29:49] <PPK> because lua is on string operation allocate new memory, copy string to that new memory and hash that string В беседу включился sphinx и провёл свои тесты: Раскрывающийся текст Цитата(sphinx) [15:51:49] <sphinx> function OnStartup() local iStart = os.time() sMsg = "This is a test" for i = 1, 10000000 do Core.SendToProfile(2, sMsg.."|") end Core.SendToAll( tostring (os.difftime(os.time(), iStart))) end [15:52:00] <sphinx> This takes 6 seconds [15:52:22] <sphinx> And Core.SendToProfile(2, sMsg) takes only 5 [15:56:27] <sphinx> But... If I set Core.SendToProfile(2, "This is a test|") it takes 4 seconds [15:57:59] <sphinx> And in real script I do need that string operation, so you right - it will be slower to add a pipe Если вкратце: добавлять | с помощью конкатенации — плохая идея, не стоит так делать. Если обойтись без конкатенации, то ускорение в их тестах едва заметно и результаты часто совпадают с результатами без |. |
|
|
30.3.2013, 15:36
Сообщение
#32
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Ну да, что в Lua идет копирование всей строки при конкатенации, что в коде - тоже копирование всей строки.
Действительно, в Lua кроме копирования при каждом создании строки ещё и рассчитывается её хеш код. Другое дело что в хабе лишнее копирование строк можно было бы исключить, что, однако, PPK не делает |
|
|
19.10.2014, 19:07
Сообщение
#33
|
|
Активный участник Группа: Пользователи Сообщений: 61 Регистрация: 24.10.2008 Из: Moscow Пользователь №: 875 Спасибо сказали: 0 раз |
Сообщение 23.9.2010, 11:09 от Setuper Частое действие в скриптах - это проверка сообщения чата на ввод пользователем какой-либо команды. Практически в каждом скрипте делается данная проверка. Данное действие должно быть максимально оптимизировано. Наиболее оптимизированный вариант: Код function ChatArrival(tUser, sData) local iPos = #tUser.sNick + 4 if sData:sub(iPos, iPos):find('!', 1, true) then --поиск префикса команды -- дальнейшие действия (в том числе поиск и сравнение команд) end end В чём преимущество? В таком использовании метод find работает очень эффективно, так как, во-первых, регулярные выражения отключены, во-вторых, строки сравниваются блоками в памяти (такое сравнение практически мгновенное). Представим на мгновение что поиск команд осуществляется каждый раз, когда мы пишем сообщение в чат, да ещё и не один раз, а столько раз, в скольких скриптах используются команды. Предложенный вариант поиска основан на поиске единого префикса команд, ведь команды юзаются пользователями относительно редко, а сообщения чата практически никогда не начинаются с указанного префикса. Применяя предложенный вариант в своих скриптах, мы по максимуму оптимизируем события чата Возник вопрос. Использование сравнения более производительно, чем использование метода find? какой код более производительный? Код function ChatArrival(tUser, sData) local iPos = #tUser.sNick + 4 if sData:sub(iPos, iPos) == '!' then --поиск префикса команды -- дальнейшие действия (в том числе поиск и сравнение команд) end end или Код function ChatArrival(tUser, sData)
local iPos = #tUser.sNick + 4 if sData:sub(iPos, iPos):find('!', 1, true) then --поиск префикса команды -- дальнейшие действия (в том числе поиск и сравнение команд) end end |
|
|
20.10.2014, 10:24
Сообщение
#34
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Да, действительно, find - это лишнее, ведь у нас остался 1 символ.
Простое сравнение уместнее. |
|
|
Похожие темы
Тема | Ответов | Автор | Просмотров | Последнее сообщение | |
---|---|---|---|---|---|
От: Способы Повышения Производительности От темы с ID: 1018 |
2 | Setuper | 6 632 | 2.2.2009, 3:13 Посл. сообщение: Setuper |
|
Сейчас: 22.11.2024, 21:16 |