Доступ к готовым решениям

Переход в группу "Пользователь"

300.00
Одноразовый платёж
Быстрый переход в группу "Пользователи", без надобности написания постов и ожидания.

Покупка дает возможность:
Быть полноправным участником форума
Нормальное копирование кода
Создавать темы
Скачивать файлы
Доступ к архиву Pawno-Info

Урок Единая тема оптимизации v1 | v2

Статус
В этой теме нельзя размещать новые ответы.

Doc_Slove

Изучающий
Пользователь
Регистрация
5 Июл 2011
Сообщения
465
Лучшие ответы
0
Репутация
246
Здравствуйте, изначально я опубликовал этот пост на стороннем форуме, но позже решил, что и тут он не навредит.

Итак, для начала нужно поговорить о коллбэке OnPlayerUpdate.

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

На замену хорошо подойдёт таймер с интервалом в 1 секунду.

Вроде с этим можно заканчивать.

Принудительно пару советов:

1. Старайтесь использовать как можно меньше таймеров
2. Если функция используется 1 раз, лучше не создавать её отдельно, а использовать напрямую или через макрос

Теперь перейдём к оптимизации.

1. JIT compiler

Он переводит AMX байт-код (код созданный компилятором PAWN) в машинный x86-код, во время выполнения, чтобы ускорить выполнение скрипта.
На самом деле JIT Compiler во много раз ускоряет выполнение скрипта (кода).

В топике, где размещён плагин, размещены и тесты:

Без JIT:
Код:
Test "floatrandom1" finished: 2684ms (3725782.5/sec)
Test "IsPlayerAimingAt" finished: 3004ms (332889.5/sec)
Test "GetPlayerCameraAimVector" finished: 192ms (5208333.5/sec)
С использованием плагина JIT Compiler:
Код:
Test "floatrandom1" finished: 715ms (13986014.0/sec)
Test "IsPlayerAimingAt" finished: 2301ms (434593.6/sec)
Test "GetPlayerCameraAimVector" finished: 22ms (45454548.0/sec)
Ну тут без лишних слов всё итак понятно.

Если вдруг JIT крашит сервер, попробуйте запустить samp-server.exe с параметром ProcDump и укажите .dmp файл для него. Для этого откройте командную строку, перейдите в каталог с вашим сервером и выполните следующую команду:
PHP:
path/to/procdump.exe -e -ma -x samp-server.exe samp-server.dmp
Официальная тема JIT Compiler v0.3.2:

2. Строки

Почитайте очень полезный урок от Триггера, который объяснит почему нельзя использовать большие стринги [Перейти]

Ни в коем случае не возвращайте в функциях/колбэках строки, подробнее: [Перейти]

3. Возвраты

Возьмём за пример функцию:

PHP:
new Float:health;
for (new i = 0; i < MAX_PLAYERS; i++)
{
	if IsPlayerConnected(i) *then
	{
		GetPlayerHealth(i, health);
		SetPlayerHealth(i, health + 10.0);
	}
}
Теперь посмотрим как она выглядит в оптимизированном виде:

PHP:
new Float:health;
for (new i, z = GetMaxPlayers(); i != z; i++)
{
	if !IsPlayerConnected(i) *then continue; //Если игрок не подключен, то цикл пропустит итерацию
	if GetPlayerHealth(i, health) *then SetPlayerHealth(i, health + 10.0);
}
Обратите внимание на изменения, второй способ работает гораздо быстрее.

4. Циклы

Вот пример оптимизированного цикла:

PHP:
for(new i=GetMaxPlayers( )-1; i != -1; i--)
{
    if !IsPlayerConnected(i) *then continue; //В некоторых случаях лучше поставить проверку на флаг логина (если не залогинен)
    //Действие
}
Это один из способов оптимизации циклов игроков.

Второй (более быстрый) способ от пользователя официального форума Y_Less'а.

Он создал инклуд под названием foreach и сейчас я постараюсь объяснить как им пользоваться.

Пример:
PHP:
foreach(Player, i)
{
    //Действие
}
Это очень быстрый метод сканирования игроков, постараюсь объяснить.

Допустим играют на сервере 3 человека, id последнего - 25.
Цикл foreach сделает 3 итерации, в отличии от остальных.

Скачать foreach:

Подключать его легко, закиньте его в папку include в вашей папке с pawno и далее в моде/скрипте/инклуде:

PHP:
#include foreach
На дворе 21 век и люди придумали новые способы оптимизации, правда представить их я вам не могу.

5. Функции

В стандартном GF функции создаются примерно так:

PHP:
forward Func(playerid, gunid);
public Func(playerid, gunid)
{
    return true;
}
Есть ещё 2 способа создания функций и они намного быстрее, нежели первый:

PHP:
stock  Func(playerid, gunid)
{
}

Func(playerid, gunid)
{
}
Таким образом создавать функции намного удобнее и лучше, кстати, я рекомендую способ напрямую создания функции (Func (playerid, gunid) ), т.к если функция в коде не применялось, то компилятор выдаст warining.

6. Переменные MAX_PLAYERS

Часто сталкивался с таким кодом как:

PHP:
new Player[MAX_PLAYERS];

public OnPlayerConnect(playerid)
{
    Player[playerid] += 1;
}
Дефолтно переменная MAX_PLAYERS равна 500.

Т.е мы создаём массив с 500 ячейками, а если максимальное кол-во слотов на сервере - 100, то для этого используем следующий код:

PHP:
#undef MAX_PLAYERS // Раздефайним макрос MAX_PLAYERS
#assert MAX_PLAYERS > 0
#define MAX_PLAYERS = 100; //Объявим константу, равную 100
Вот так, ещё 1 плюс к оптимизации

7. Получение имени игрока

Всё чаще начал замечать следующую функцию для получения ника игрока:

PHP:
forward GN(playerid);
public GN(playerid)
{
new PlayerName[MAX_PLAYER_NAME];
GetPlayerName(playerid,PlayerName,sizeof(PlayerName));
return PlayerName;
}
Категорически не рекомендую это использовать, т.к у данной функции есть 2 больших минуса:

1. При каждом использовании объявляется функция PlayerName
2. Функция возвращает строку, а это не хорошо

Вот как можно это оптимизировать, но не упростить:

В энуменатор игроков добавляем переменную:
PHP:
pName[MAX_PLAYER_NAME]
В public OnPlayerConnect :
PHP:
GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
Далее ко всем макросам:
#define GN(%1) PlayerInfo[%1][pName]

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

Пример использования:

PHP:
printf("%s был замечен на сервере", GN(playerid));

8. Switch vs Оператор ветвления if/else/else if

В большинстве случаев оператор switch выигрывает в скорости.

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

К примеру диалоги, в большинстве модах много диалогов и оператором if их перебирать не разумно.

Приведём пример как было:

PHP:
if(dialogid == 100)
{
    if(response)
    {
    if(listitem == 0)
    {
       print("1");
    }
    if(listitem == 1)
    {
        print("1");
    }
    if(listitem == 2)
    {
        print("1");
    }
    if(listitem == 3)
    {
        print("2");
    }
    if(listitem == 4)
    {
        print("3");
    }
    if(listitem == 5)
    {
        print("2");
    }
    }
}
else if(dialogid == DIALOG_LOGIN)
{
    if(response)
    {
       //Действие
    }
}
и как стало:

PHP:
switch(dialogid)
{
    case 100:
    {
        if(!response) return true;
        switch(listitem)
        {
            case 0..2: print("1");
            case 3,5: print("2");
            case 4: print("3");

        }
    }
    case DIALOG_LOGIN:
    {
        if(!response) return 1;
    }
}
В каких случаях лучше использовать switch:
Следующая конструкция:
PHP:
switch(var)
{
        case 40,80,150,160,230,420: return 1;
}
быстрее, чем

PHP:
if ( var == 40 || var == 80 || var == 150 || var == 160 || var == 230 || var == 420 ) return 1;
Следующая конструкция:

PHP:
switch(var)
{
        case 40..80,150..160,230..420: return 1;
}
медленнее чем

PHP:
if ( var >= 40 && var <= 80 || var >= 150 && var <= 160 || var >= 230 && var <= 420 ) return 1;
Следующая конструкция:

PHP:
switch(var)
{
        case 40: return 1;
}
одинакова как и

PHP:
if ( var == 40 ) return 1;
Следующая конструкция:

PHP:
switch(var)
{
        case 40..50: return 1;
}
быстрее чем

PHP:
if ( var >= 40 && var <= 50 ) return 1;

9. Команды

Наиболее быстрый плагин для создания команд - DC_CMD

Вот ссылка: http://pawno-info.ru/showthread.php?t=154792

Если вам не понятно как теперь создавать команды, воспользуйтесь данной темой:
Подробный мануал по использованию: [Перейти]

10. Рейты

Ещё одна немаловажная часть, это рейты.
При правильной настройке снизится пинг, лаги, нагрузка и пр.

Итак, заходим в server.cfg и там:

Если на вашем сервере играет до 100 человек, то:

PHP:
onfoot_rate 40
incar_rate 40
weapon_rate 40
stream_distance 400.0
stream_rate 500
Если на вашем сервере играет от 100 до 200 игроков, то:

PHP:
onfoot_rate 40
incar_rate 40
weapon_rate 40
stream_distance 300.0
stream_rate 1000
Если же на вашем сервере играет от 200 до 500 игроков, то:

PHP:
onfoot_rate 50
incar_rate 50
weapon_rate 50
stream_distance 200.0
stream_rate 2000
onfoot_rate - время в мили секундах за которое будут обновляться координаты перемещения игроков (в ходьбе).
incar_rate - время в мили секундах для обновления позиции транспорта на котором ездят игроки.
weapon_rate - время в мили секундах обновления попадания оружия.
stream_distance - расстояние от игрока к объекту в зоне видимости.
stream_rate - время в мили секундах за которое будут обновляться данные от игрока к объекту.

10. Оптимизация потребления памяти

Приведу простой пример оптимизации потребления памяти на переменных.

Возьмём для примера 2 переменные:
1.
PHP:
new a[MAX_PLAYERS];
a[1] = 100;
2.
PHP:
new a[MAX_PLAYERS char];
a{1} = 100;
heapspace MAX_PLAYERS: 2004
heapspace MAX_PLAYERS char: 504

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

Фигурные скобки обозначают, что мы обращаемся к байту, а не к ячейке и главной нашей проблемой является то, что 1 байт хранит значения от 0 до 255 (включительно).
А это значит, что использовать char нужно осмотрительно и с умом.

Ещё 1 урок, написанный мной, сильно поможет вам значительно сэкономить память: [Перейти]

Урок будет пополняться!
 
Последнее редактирование:
Статус
В этой теме нельзя размещать новые ответы.
Сверху Снизу