shape1
shape2
shape3
shape4
shape7
shape8

Оптимизация | Индивидуальные таймеры


Статус
Закрыто для дальнейших ответов.

ac1nve

Продвинутый
Пользователь
23.02.2016
591
231
0
Добрый день. 

В этом уроке я хочу донести до вас довольно значимый способ оптимизации мода, который известен далеко не всем. Но сразу предупреждаю, если вы очень слабый скриптер, не читайте дальше и не пишите ничего в этой теме.
Итак, таймеры. Многие считают что использовать кучу таймеров в моде - ужасно плохо, но это не так, если использовать их разумно. Нагружают сервер действия, срабатываемые в таймере, а не сами таймеры (совсем немного). Поэтому 1000 разумно сделанных таймеров будут полезнее чем 5 кое-как сделанных. Если вы это понимаете - идём дальше, иначе закрывайте тему.

Почти в каждом моде есть таймер, допустим на 1 секунду. В этом таймере есть цикл на всех игроков сервера, где с ними производятся действия. Например:

public Timer1Second()
{
foreach(...)
{
// Действия
}
return 1;
}

Именно из за таких таймеров серверы с большим онлайном начинают испытывать лаги и ищут более мощный хостинг. Всё дело в том, что одно срабатывание из foreach (для одного игрока) проходит например за 0.25 - 1 мс (в зависимости от оптимизации и мощности процессора), что впрочем то не так уж и страшно. Но когда игроков 200, выполнение таймера занимает уже от 50 мс до 200 мс каждую секунду и пока весь таймер не закончит своё действие, сервер своими делами не займётся (синхронизация игроков и т.п.), поэтому в эти 200 мс сервер тупо висит - вот она причина лагов. Теперь давайте разберём как избавиться от этого и не мешать серверу заниматься необходимыми для работы сервера делами.

1) Убрать из ВСЕХ таймеров такие циклы с игроками. 

2) Объявить глобальный массив (ко всем new):

new PlayerTimerID[MAX_PLAYERS];  
3) Ко всем forward:

forward PlayerUpdate(playerid);

4) В OnPlayerConnect:

PlayerTimerID[playerid] = SetTimerEx("PlayerUpdate", 250, 1, "d", playerid);

5) В OnPlayerDisconnect:

KillTimer(PlayerTimerID[playerid]);

6) В конце мода:

public PlayerUpdate(playerid)
{
return 1;
}

В итоге мы получим индивидуальный таймер для каждого игрока, да, их будет 1000 при максимальном онлайне, но ничего страшного - серверу только лучше. Теперь все действия с игроком нужно использовать в PlayerUpdate (он срабатывает каждые 250 мс). Отдельные таймеры на 1 сек и т.п. создавать не нужно, просто подсчитывайте количество срабатываний PlayerUpdate (1 сек = 4 срабатывания) и выполняйте нужные действия.

И что же нам это всё даст? Когда сервер выполнял цикл, он выполнял его полностью на всех игроков и пока не закончил - другими делами не занимался. В нашем случае для каждого игрока идут отдельные таймеры, срабатывающие в разное время, а не сразу все. Поэтому между срабатываниями таймеров, пусть оно будет даже 0,01 мс, но сервер в это время займётся своими делами и ему хватит этого времени, а значит сервер не будет останавливаться в ожидании.

На этом всё, надеюсь что объяснил достаточно понятно. Удачного скриптинга!

Автор: XemyL

 
Последнее редактирование модератором:

LeonYT

Освоившийся
Пользователь
04.09.2016
56
15
0
25
Ещё довольно хорошим способом оптимизации является использование итераторов в foreach. Посредством использования итераторов кол-во повторений цикла можно уменьшить в разы.

 

noname_idk

Гуру
Пользователь
19.07.2015
4 046
7
787
0
Скриптер
@LeonYT, речь в данной теме идет исключительно об индивидуальных таймерах. Более того, автор склоняется к тому, что не нужно в регулярно вызываемых таймерах делать перебор игроков, а не о том, как сократить количество повторений цикла.

 

LeonYT

Освоившийся
Пользователь
04.09.2016
56
15
0
25
@Elrmrnt-Kritik, просто в теме упоминается использование foreach как не самое целесообразное (в данном случае). Я же так не считаю и упомянул о итераторах, подразумевая их использование не в конкретно данной ситуации. В глобальных таймерах использование циклов действительно является не самым хорошим вариантом.

 
Статус
Закрыто для дальнейших ответов.