PDA

Просмотр полной версии : [Мануал] Проверка на AFK(Свёрнуто ли окошко SA)



James_Cruise
16.10.2014, 13:37
После include


#define AFK_WINDOW_TIME 1200// 1200 мс - время последнего обновления статуса с сервером.
new AFK_window[MAX_PLAYERS];


В public OnPlayerUpdate(playerid)


AFK_window[playerid] = GetTickCount();


И сама проверка


if(GetTickCount() - AFK_window[playerid] > AFK_WINDOW_TIME)
{
SendClientMessage(playerid, -1, "AFK");
}

NewGreen
16.10.2014, 13:58
Такой метод определения AFK имеет право на существование, но лучше все же не использовать функцию GetTickCount() это лишнее можно обойтись булевыми переменными, например:



new bool:checkToAFK[MAX_PLAYERS];


OnPlayerUpdate(playerid)


checkToAFK[playerid] = false;


И проверку этого в сек таймер


if(checkToAFK[playerid]) {
// Выполняем АФК функции
}
checkToAFK[playerid] = true;


Я не хочу наступать на горло вашей песни, но думаю что с булевыми переменными, код будет эффективней

James_Cruise
16.10.2014, 16:58
В каком то плане ваш способ будет лучше.
Не учитывая,что в вашем способе нужен таймер.
Такой метод определения AFK имеет право на существование, но лучше все же не использовать функцию GetTickCount() это лишнее можно обойтись булевыми переменными, например:



new bool:checkToAFK[MAX_PLAYERS];


OnPlayerUpdate(playerid)


checkToAFK[playerid] = false;


И проверку этого в сек таймер


if(checkToAFK[playerid]) {
// Выполняем АФК функции
}
checkToAFK[playerid] = true;


Я не хочу наступать на горло вашей песни, но думаю что с булевыми переменными, код будет эффективней

NewGreen
16.10.2014, 17:21
В каком то плане ваш способ будет лучше.
Не учитывая,что в вашем способе нужен таймер.
Ну если учесть что в большинстве модов присутствует так или иначе, 1 сек таймер, думаю что под АФК не понадобиться заводить его отдельно, достаточно поставить проверку на АФК в функцию с этим таймером. Но даже если, и создать лишний таймер (если отсутствует общий 1 сек или налогичный ему) в этом нет ничего страшного.

James_Cruise
16.10.2014, 18:19
Опять же, нужно создать таймер.
А теперь представим,что у нас система которая не проходит через таймер,но нуждается в проверке АФК.
В твоём случае мы проверяем таким образом:

if(!checkToAFK[playerid]) {
// Игрок не АФК
}
Значит для выполнения итерации переменная checkToAFK[playerid] должна ровняться false,учитывая,что OnPlayerUpdate может вызываться от 0 до 25 раз в секунду,допустим игрок стоит вызов будет от 0 до 5 раз в секунду,пускай в среднем будет каждые 200 мс,теперь у нас срабатывает таймер, checkToAFK[playerid] = true ,затем сработает проверка выше,а только тогда OnPlayerUpdate и в данном случае у нас баг.

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

wAx
16.10.2014, 20:20
AFK_window[playerid] = GetTickCount();

Всяко лучше каждый раз устанавливать значение afk = false, чем afk = GetTickCount()..
Даже если система не проходит через основной таймер, все равно можно будет проверить статус игрока.

Daniel_Cortez
16.10.2014, 22:30
думаю что с булевыми переменными, код будет эффективней
Вы серьёзно? В Pawn все типы данных, кроме массивов, занимают по 4 байта.

James_Cruise
17.10.2014, 03:17
Проверить то можно,но будут неточности,точнее баг.

AFK_window[playerid] = GetTickCount();

Всяко лучше каждый раз устанавливать значение afk = false, чем afk = GetTickCount()..
Даже если система не проходит через основной таймер, все равно можно будет проверить статус игрока.

NewGreen
17.10.2014, 10:20
Опять же, нужно создать таймер.
А теперь представим,что у нас система которая не проходит через таймер,но нуждается в проверке АФК.
В твоём случае мы проверяем таким образом:

if(!checkToAFK[playerid]) {
// Игрок не АФК
}

Значит для выполнения итерации переменная checkToAFK[playerid] должна ровняться false,учитывая,что OnPlayerUpdate может вызываться от 0 до 25 раз в секунду,допустим игрок стоит вызов будет от 0 до 5 раз в секунду,пускай в среднем будет каждые 200 мс,теперь у нас срабатывает таймер, checkToAFK[playerid] = true ,затем сработает проверка выше,а только тогда OnPlayerUpdate и в данном случае у нас баг.
Спасибо! Я понял что вы хотите сказать, что касается описания вами работы алгоритма, это нужно проверять, теоретически он работает, но также теоретически может возникнуть баг (хотя это багом назвать трудно). Учитывая что вы переписали первоначальную реализацию с


if(checkToAFK[playerid]) {
// Выполняем АФК функции
}
checkToAFK[playerid] = true;

на


if(!checkToAFK[playerid]) {
// Игрок не АФК
}

я не могу вам гарантировать нормальную работу алгоритма.
Немного теории:
OnPlayerUpdate - обновляется очень быстро, и работает пока игрок не свернул игру, соответственно переменная checkToAFK[playerid] будет иметь значение false до тех пор пока игрок не свернет игру, как только он игрок свернул игру, система определяется что игрок АФК, именно благодаря этому коду в 1 сек таймере:


if(checkToAFK[playerid]) {
// Выполняем АФК функции
}
checkToAFK[playerid] = true;


- - - Добавлено - - -


Вы серьёзно? В Pawn все типы данных, кроме массивов, занимают по 4 байта.
Ну что поделать, Pawn изначально создавался для неопытных программистов, наверное поэтому создатели были столь щедры))
конечно, не очень рационально под boolean выделять 4 байта, но что поделаешь.
Под эффективностью я имел ввиду, что присваивание значение переменной в конкретном случае, однозначно быстрее чем вызов функции и присваивание её значения той же переменной.

Daniel_Cortez
17.10.2014, 11:54
Ну что поделать, Pawn изначально создавался для неопытных программистов, наверное поэтому создатели были столь щедры))
конечно, не очень рационально под boolean выделять 4 байта, но что поделаешь.
В Pawn обычно не используется такое понятие, как "байт", вместо этого используется понятие "ячейка". В версии Pawn для SA:MP ячейка равна 4 байтам, хотя в других версиях (например, для Vault-MP) она может состоять из 8 байт. На каждую переменную выделяется по 1 ячейке, поэтому нельзя сделать одиночные переменные размером всего в 1 байт.
Впрочем, можно сделать массив из байтов:

new arr[12 char];
Этим кодом создастся массив из 12 байт (12/4 = 3 ячейки).
Затем присваиваем ячейке значение:

arr{playerid} = 1;
Обратите внимание: вместо квадратных скобок используются фигурные - они означают доступ вместо всей ячейки только к байту с указанным индексом.


Под эффективностью я имел ввиду, что присваивание значение переменной в конкретном случае, однозначно быстрее чем вызов функции и присваивание её значения той же переменной.
Хорошенько подумайте, что будет, если в том же односекундном таймере добавить код с проверкой на AFK _после_ присвоения checkToAFK[playerid] = true.

James_Cruise
17.10.2014, 12:15
но также теоретически может возникнуть баг (хотя это багом назвать трудно)
А именно?


я не могу вам гарантировать нормальную работу алгоритма.
Вся суть вашего "эффективного" алгоритма.


Немного теории:
OnPlayerUpdate - обновляется очень быстро, и работает пока игрок не свернул игру, соответственно переменная checkToAFK[playerid] будет иметь значение false до тех пор пока игрок не свернет игру, как только он игрок свернул игру, система определяется что игрок АФК, именно благодаря этому коду в 1 сек таймере:

if(checkToAFK[playerid]) {
// Выполняем АФК функции
}
checkToAFK[playerid] = true;

OnPlayerUpdate может вызваться 1 раз в секунду,учитывая что SA не свёрнута.

Seregamil
17.10.2014, 12:31
А именно?


Вся суть вашего "эффективного" алгоритма.



OnPlayerUpdate может вызваться 1 раз в секунду,учитывая что SA не свёрнута.

Вопрос о вызове сего каллбэка был решен давно.

Daniel_Cortez
17.10.2014, 12:59
OnPlayerUpdate может вызваться 1 раз в секунду,учитывая что SA не свёрнута.
http://wiki.sa-mp.com/wiki/OnPlayerUpdate

http://breedpmnr.ru/i/BBF552

NewGreen
17.10.2014, 16:40
В Pawn обычно не используется такое понятие, как "байт", вместо этого используется понятие "ячейка". В версии Pawn для SA:MP ячейка равна 4 байтам, хотя в других версиях (например, для Vault-MP) она может состоять из 8 байт. На каждую переменную выделяется по 1 ячейке, поэтому нельзя сделать одиночные переменные размером всего в 1 байт.
Впрочем, можно сделать массив из байтов:

new arr[12 char];
Этим кодом создастся массив из 12 байт (12/4 = 3 ячейки).
Затем присваиваем ячейке значение:

arr{playerid} = 1;
Обратите внимание: вместо квадратных скобок используются фигурные - они означают доступ вместо всей ячейки только к байту с указанным индексом.

Еще можно обмануть систему переменных под которые выделяются 4 байта (не удобно писать 1 ячейка :-) ) и использовать массивы например так для целых чисел:


new arr[1 char]; // итого 1 байт

правда далеко на 1 байте не уедешь)) но можно использовать для небольших чисел.
Так же можно и поступать со строками (аля массивами):


new str[10+1 char]; // плюс 1 на завершающий символ строки



Хорошенько подумайте, что будет, если в том же односекундном таймере добавить код с проверкой на AFK _после_ присвоения checkToAFK[playerid] = true.
В целом система писалась на коленке, могу расписать немного подробно:
К глобальным переменным:


new bool:checkToAFK[MAX_PLAYERS];


Где то в моде сферический код в вакууме:


public OnPlayerUpdate(playerid)
{
checkToAFK[playerid] = false; // пока окно игрок активен система его игнорит
}
public OnGameModeInit()
{
SetTimer("SomeFunc",1000,true);
}
public SomeFunc() // опустил forward
{
for(new i = 0; i < MAX_PLAYERS; i++)
{
if(checkToAFK[i]) //
{
SendClientMessage(i,-1,"AFK"); // тут что угодно, действия при АФК
}
checkToAFK[playerid] = true; // если игрок свернул игру **
}
return 1;
}


** - при сворачивании игры переменная принимает значение true и условие if(checkToAFK[i]) нахождения в АФК начинает выполняться.

В принципе я не вижу здесь никаких других сценариев, есть правда некоторая вероятность того, что переменная checkToAFK[playerid] может быть переключена случайна на true, но она очень маленькая.

- - - Добавлено - - -


А именно?
О баге я написал в посте к Daniel_Cortez чуть выше почитайте.


Вся суть вашего "эффективного" алгоритма.

Это суть не моего алгоритма, а вашего, который вы переписали уже из моего, и не нужно вырывать слова из контекста, этим вы не меняете сути дела, а лишь пытаетесь зацепиться за что либо с целью искажения реального положения вещей :wacko:.


OnPlayerUpdate может вызваться 1 раз в секунду,учитывая что SA не свёрнута.

Опять же выше предоставили необходимые ссылки на ваше утверждение.

^_^
17.10.2014, 17:26
Еще можно обмануть систему переменных под которые выделяются 4 байта (не удобно писать 1 ячейка :-) ) и использовать массивы например так для целых чисел:


new arr[1 char]; // итого 1 байт

правда далеко на 1 байте не уедешь)) но можно использовать для небольших чисел.
Так же можно и поступать со строками (аля массивами):


new str[10+1 char]; // плюс 1 на завершающий символ строки


В целом система писалась на коленке, могу расписать немного подробно:
К глобальным переменным:


new bool:checkToAFK[MAX_PLAYERS];


Где то в моде сферический код в вакууме:


public OnPlayerUpdate(playerid)
{
checkToAFK[playerid] = false; // пока окно игрок активен система его игнорит
}
public OnGameModeInit()
{
SetTimer("SomeFunc",1000,true);
}
public SomeFunc() // опустил forward
{
for(new i = 0; i < MAX_PLAYERS; i++)
{
if(checkToAFK[i]) //
{
SendClientMessage(i,-1,"AFK"); // тут что угодно, действия при АФК
}
checkToAFK[playerid] = true; // если игрок свернул игру **
}
return 1;
}


** - при сворачивании игры переменная принимает значение true и условие if(checkToAFK[i]) нахождения в АФК начинает выполняться.

В принципе я не вижу здесь никаких других сценариев, есть правда некоторая вероятность того, что переменная checkToAFK[playerid] может быть переключена случайна на true, но она очень маленькая.

- - - Добавлено - - -


О баге я написал в посте к Daniel_Cortez чуть выше почитайте.



Это суть не моего алгоритма, а вашего, который вы переписали уже из моего, и не нужно вырывать слова из контекста, этим вы не меняете сути дела, а лишь пытаетесь зацепиться за что либо с целью искажения реального положения вещей :wacko:.



Опять же выше предоставили необходимые ссылки на ваше утверждение.
http://risovach.ru/upload/2013/03/generator/uporotyy_13635231_orig_.jpeg

James_Cruise
17.10.2014, 18:05
Еще можно обмануть систему переменных под которые выделяются 4 байта (не удобно писать 1 ячейка :-) ) и использовать массивы например так для целых чисел:


new arr[1 char]; // итого 1 байт

правда далеко на 1 байте не уедешь)) но можно использовать для небольших чисел.
Так же можно и поступать со строками (аля массивами):


new str[10+1 char]; // плюс 1 на завершающий символ строки


В целом система писалась на коленке, могу расписать немного подробно:
К глобальным переменным:


new bool:checkToAFK[MAX_PLAYERS];


Где то в моде сферический код в вакууме:


public OnPlayerUpdate(playerid)
{
checkToAFK[playerid] = false; // пока окно игрок активен система его игнорит
}
public OnGameModeInit()
{
SetTimer("SomeFunc",1000,true);
}
public SomeFunc() // опустил forward
{
for(new i = 0; i < MAX_PLAYERS; i++)
{
if(checkToAFK[i]) //
{
SendClientMessage(i,-1,"AFK"); // тут что угодно, действия при АФК
}
checkToAFK[playerid] = true; // если игрок свернул игру **
}
return 1;
}


** - при сворачивании игры переменная принимает значение true и условие if(checkToAFK[i]) нахождения в АФК начинает выполняться.

В принципе я не вижу здесь никаких других сценариев, есть правда некоторая вероятность того, что переменная checkToAFK[playerid] может быть переключена случайна на true, но она очень маленькая.

- - - Добавлено - - -


О баге я написал в посте к Daniel_Cortez чуть выше почитайте.



Это суть не моего алгоритма, а вашего, который вы переписали уже из моего, и не нужно вырывать слова из контекста, этим вы не меняете сути дела, а лишь пытаетесь зацепиться за что либо с целью искажения реального положения вещей :wacko:.



Опять же выше предоставили необходимые ссылки на ваше утверждение.

wat?

Как бы вы там не доказывали,ваш алгоритм в каком то плане быдловат. Не огорчайтесь, но это факт.
Я не говорю за лишние проверки, вот элементарное, неточности ...

NewGreen
17.10.2014, 18:24
wat?

Как бы вы там не доказывали,ваш алгоритм в каком то плане быдловат. Не огорчайтесь, но это факт.
Я не говорю за лишние проверки, вот элементарное, неточности ...
Прошу по пунктам расписать:
1) чем же алгоритм быдловат - и что вообще вы подразумеваете под быдлокодом
2) лишние проверки - опишите где вы увидели лишние проверки, там так же одна проверка как и у вас
3) неточности - что вы подразумеваете под этим

От себя добавлю, не неточности а лишь вероятность, а вероятность понятие достаточно неопределенное, она может быть как 1 так и 0.000001 а может быть вообще 0.

James_Cruise
17.10.2014, 19:04
1) Есть реализованный алгоритм афк,без вcяких "вероятностей",и использованием таймера.
2) Читаем пункт 1.
3) Читаем комментарий #5.
Прошу по пунктам расписать:
1) чем же алгоритм быдловат - и что вообще вы подразумеваете под быдлокодом
2) лишние проверки - опишите где вы увидели лишние проверки, там так же одна проверка как и у вас
3) неточности - что вы подразумеваете под этим

От себя добавлю, не неточности а лишь вероятность, а вероятность понятие достаточно неопределенное, она может быть как 1 так и 0.000001 а может быть вообще 0.

NewGreen
17.10.2014, 19:24
1) Есть реализованный алгоритм афк,без вcяких "вероятностей",и использованием таймера.
2) Читаем пункт 1.
3) Читаем комментарий #5.
В любом алгоритме так или иначе есть вероятность ошибки.
Использование таймера, вы уже несколько раз в этой ветке упомянули это предложение, чем так плохи таймеры ?

James_Cruise
17.10.2014, 20:00
В данном случае,ваш алгоритм более неточный,тут и ослу понятно.
Я не говорил что таймеры плохи,я говорю,что можно обойтись без него.
В любом алгоритме так или иначе есть вероятность ошибки.
Использование таймера, вы уже несколько раз в этой ветке упомянули это предложение, чем так плохи таймеры ?

NewGreen
17.10.2014, 20:41
В данном случае,ваш алгоритм более неточный,тут и ослу понятно.
Я не говорил что таймеры плохи,я говорю,что можно обойтись без него.
Еще раз Вероятность != неточность или точность, это разные понятия.
В принципе на этом можно и завершить дискуссию, она ни к чему не приведет.

Daniel_Cortez
17.10.2014, 22:37
Еще можно обмануть систему переменных под которые выделяются 4 байта (не удобно писать 1 ячейка :-) ) и использовать массивы например так для целых чисел:


new arr[1 char]; // итого 1 байт

правда далеко на 1 байте не уедешь)) но можно использовать для небольших чисел.
Чушь. Кол-во выделяемой памяти выравнивается по размеру ячейки, поэтому под 1 байт выделится 1 ячейка - 4 байта. И так далее: 2-4, 3-4, 4-4, 5-8, 6-8, 7-8, 8-8, 9-12, ...



В принципе я не вижу здесь никаких других сценариев, есть правда некоторая вероятность того, что переменная checkToAFK[playerid] может быть переключена случайна на true, но она очень маленькая.

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

NewGreen
18.10.2014, 09:26
Чушь. Кол-во выделяемой памяти выравнивается по размеру ячейки, поэтому под 1 байт выделится 1 ячейка - 4 байта. И так далее: 2-4, 3-4, 4-4, 5-8, 6-8, 7-8, 8-8, 9-12, ...

Согласен. Спасибо за информацию!



Погоня за мифической оптимизацией - не оправдание увеличению вероятности возникновения ошибок.
В первую очередь, система должна быть максимально надёжной.
Насчет мифической оптимизации - это как раз про Pawn с его виртуальной машиной, т.к. что работает эффективно в одном языке в Pawn наоборот, даже элементарное деление работает быстрее чем побитовый сдвиг. Сам язык не развивается, и говорить про оптимизации на нем не совсем корректно.
Насчет вероятности возникновения ошибок - код приведенный выше, должен работать без ошибок, а вероятность есть в любом алгоритме, она может зависеть не только от не/корректности алгоритма, но, и от внешних факторов.
Если я сказал что она есть - то это не значит что баг обязательно появиться, в нормально построенном моде/программе, алгоритм будет работать идеально!

Daniel_Cortez
18.10.2014, 13:19
даже элементарное деление работает быстрее чем побитовый сдвиг
Смелое утверждение. А теперь докажите свою теорию.



Если я сказал что она есть - то это не значит что баг обязательно появиться

Насчет вероятности возникновения ошибок - код приведенный выше, должен работать без ошибок, а вероятность есть в любом алгоритме, она может зависеть не только от не/корректности алгоритма, но, и от внешних факторов.

В односекундном таймере после присвоения массиву true может быть добавлен и другой пользовательский код.
Между вызовом односекундного таймера и OnPlayerUpdate может быть вызван другой коллбэк, причём не один.

Можете защищать свой индусский код сколько угодно, но факт есть факт - в алгоритме есть ошибки и он будет работать неправильно.



в нормально построенном моде/программе, алгоритм будет работать идеально!
Очередная голословная отговорка.

NewGreen
18.10.2014, 14:04
Смелое утверждение. А теперь докажите свою теорию.


#include <a_samp>

main() {
new workTime = GetTickCount();
new val = 0;
for(new i = 0; i < 1000000; i++) {
val = i*2;
val /=2;
}
printf("div time = %d",GetTickCount() - workTime);
val = 0;
workTime = GetTickCount();
for(new i = 0; i < 1000000; i++) {
val = i<<1;
val >>= 1;
}
printf("Shift time = %d",GetTickCount() - workTime);
}


div time = 39
Shift time = 58

Сравнение операторов умножения и деления с операторами побитового сдвига.




В односекундном таймере после присвоения массиву true может быть добавлен и другой пользовательский код.
Между вызовом односекундного таймера и OnPlayerUpdate может быть вызван другой коллбэк, причём не один.

Можете защищать свой индусский код сколько угодно, но факт есть факт - в алгоритме есть ошибки и он будет работать неправильно.


Очередная голословная отговорка.

Удачи в написании нового RLS.
Я не занимаюсь модостроительством не моя сфера деятельности, то что могут быть ошибки говорил с самого начала.
Этот код лишь шаблон, не нужно делать столь критические выводы.

Daniel_Cortez
18.10.2014, 17:51
#include <a_samp>

main() {
new workTime = GetTickCount();
new val = 0;
for(new i = 0; i < 1000000; i++) {
val = i*2;
val /=2;
}
printf("div time = %d",GetTickCount() - workTime);
val = 0;
workTime = GetTickCount();
for(new i = 0; i < 1000000; i++) {
val = i<<1;
val >>= 1;
}
printf("Shift time = %d",GetTickCount() - workTime);
}


div time = 39
Shift time = 58
Вы ещё на 100 или даже на 10 итераций потестируйте - тогда и format(string, sizeof(string), "%s", str) будет быстрее, чем string = str.
Ну не делает никто тесты на время меньше 1 секунды, да ещё и отдельно друг от друга - любое постороннее приложение может повысить нагрузку на ЦП, повлияв на результат теста.

Увеличим кол-во итераций и переделаем тест так, чтобы сгладить возможную разницу в нагрузке на ЦП, возникающую со временем.


#include <a_samp>

//==================================[Settings]==================================

#define PROFILE_ITERS_MAJOR 1_000_000
#define PROFILE_ITERS_MINOR 100


//====================================[Test]====================================

main()
{
print("Testing...\n");
new ticks0=0, ticks1=0, i, j, t, tmp_ticks;
for(i=0; i<PROFILE_ITERS_MAJOR; ++i)
{
tmp_ticks=GetTickCount();
for(j=0; j<PROFILE_ITERS_MINOR; ++j)
{
t = i*2;
t /= 2;
}
ticks0 += GetTickCount()-tmp_ticks;
tmp_ticks=GetTickCount();
for(j=0; j<PROFILE_ITERS_MINOR; ++j)
{
t = i<<1;
t >>= 1;
}
ticks1 += GetTickCount()-tmp_ticks;
}
printf("Multiplication/division: %d", ticks0);
printf("Shifting to the left/right: %d", ticks1);
print("\n");
}

http://s7.hostingkartinok.com/uploads/images/2014/10/f0163895da066c4122328d8f03c64743.png
Разница небольшая, но всё же есть, и далеко не в пользу операций умножения/деления.
Впрочем, не удивлюсь, если на хостинге разница в пользу операций сдвига будет куда более значительной - в версии сервера для Linux используется более эффективная реализация виртуальной машины с расширениями GNU C.
http://s7.hostingkartinok.com/uploads/images/2014/10/08d0725639164ad292e83ff029df01cf.png



то что могут быть ошибки говорил с самого начала
Тогда зачем предлагать такой код, если знаете, что в нём ошибки?
Думаете, кому-то нужен будет заведомо ненадёжный метод из-за каких-то 10-20 сэкономленных процессорных тактов? -_-

NewGreen
18.10.2014, 18:38
Вы ещё на 100 или даже на 10 итераций потестируйте - тогда и format(string, sizeof(string), "%s", str) будет быстрее, чем string = str.
Ну не делает никто тесты на время меньше 1 секунды, да ещё и отдельно друг от друга - любое постороннее приложение может повысить нагрузку на ЦП, повлияв на результат теста.

Увеличим кол-во итераций и переделаем тест так, чтобы сгладить возможную разницу в нагрузке на ЦП, возникающую со временем.


#include <a_samp>

//==================================[Settings]==================================

#define PROFILE_ITERS_MAJOR 1_000_000
#define PROFILE_ITERS_MINOR 100


//====================================[Test]====================================

main()
{
print("Testing...\n");
new ticks0=0, ticks1=0, i, j, t, tmp_ticks;
for(i=0; i<PROFILE_ITERS_MAJOR; ++i)
{
tmp_ticks=GetTickCount();
for(j=0; j<PROFILE_ITERS_MINOR; ++j)
{
t = i*2;
t /= 2;
}
ticks0 += GetTickCount()-tmp_ticks;
tmp_ticks=GetTickCount();
for(j=0; j<PROFILE_ITERS_MINOR; ++j)
{
t = i<<1;
t >>= 1;
}
ticks1 += GetTickCount()-tmp_ticks;
}
printf("Multiplication/division: %d", ticks0);
printf("Shifting to the left/right: %d", ticks1);
print("\n");
}

http://s7.hostingkartinok.com/uploads/images/2014/10/f0163895da066c4122328d8f03c64743.png
Разница небольшая, но всё же есть, и далеко не в пользу операций умножения/деления.
Впрочем, не удивлюсь, если на хостинге разница в пользу операций сдвига будет куда более значительной - в версии сервера для Linux используется куда более эффективная реализация виртуальной машины с расширениями GNU C.
http://s7.hostingkartinok.com/uploads/images/2014/10/08d0725639164ad292e83ff029df01cf.png

Позвольте узнать параметры вашего компьютера, у меня Intel Core i7 4770K – 3.50GHz. / Intel Z87/LAN ASUS Z87-PRO
и вот такие результаты кода приведенного вами:

http://s7.hostingkartinok.com/uploads/images/2014/10/278d784c8e10933c4e5b10a0484cac13.png (http://hostingkartinok.com/show-image.php?id=278d784c8e10933c4e5b10a0484cac13)


Тогда зачем предлагать такой код, если знаете, что в нём ошибки?
Думаете, кому-то нужен будет заведомо ненадёжный метод из-за каких-то 10-20 сэкономленных процессорных тактов? -_-
Скажу так, изначально я предлагал следующий вариант, вместо присваивания переменной, значение функции GetTickCount(), использовать булевые переменные с true/false, также я лишь показал пример алгоритма, при этом предупреждая о возможных недостатках, если бы я хотел кому то что то предложить, я бы создал отдельную тему.

- - - Добавлено - - -

А на Linux уже результат другой:


----------
Loaded log file: "server_log.txt".
----------

SA-MP Dedicated Server
----------------------
v0.3z, (C)2005-2014 SA-MP Team

[17:36:21] filterscripts = "" (string)
[17:36:21]
[17:36:21] Server Plugins
[17:36:21] --------------
[17:36:21] Loaded 0 plugins.

[17:36:21]
[17:36:21] Filterscripts
[17:36:21] ---------------
[17:36:21] Loaded 0 filterscripts.

[17:36:21] Testing...

[17:36:30] Multiplication/division: 4389
[17:36:30] Shifting to the left/right: 3496
[17:36:30]

[17:36:30] Number of vehicle models: 0

Daniel_Cortez
18.10.2014, 20:23
Позвольте узнать параметры вашего компьютера
Если это имеет какое-то значение, процессор Intel Pentium Dual-Core E6600 - 3.06GHz.



А на Linux уже результат другой
Что и следовало ожидать.



Скажу так, изначально я предлагал следующий вариант, вместо присваивания переменной, значение функции GetTickCount(), использовать булевые переменные с true/false, также я лишь показал пример алгоритма, при этом предупреждая о возможных недостатках, если бы я хотел кому то что то предложить, я бы создал отдельную тему.
И снова уходим от ответа.

Тогда зачем предлагать такой код, если знаете, что в нём ошибки?
Думаете, кому-то нужен будет заведомо ненадёжный метод из-за каких-то 10-20 сэкономленных процессорных тактов? -_-

NewGreen
18.10.2014, 20:41
И снова уходим от ответа.
Я могу признать что был не прав, в том что предложил заведомо недоработанный вариант алгоритма, тем не менее, акцент делался не на сам алгоритм (это был лишь набросок), а на то что в конткретном случае с системой АФК, эффективнее использовать булевые переменные как переключатель, нежели присваивать переменной значение функции.
Развели мы с вами холивар тут.

Daniel_Cortez
19.10.2014, 18:05
эффективнее использовать булевые переменные как переключатель, нежели присваивать переменной значение функции.
Эффективнее, но не приемлемее для данной ситуации. Могли бы просто подождать более удачного случая, нежели плодить быдлокодеров из тех, кто последует вашему примеру. Даже если пытаться объяснить недостатки, всё равно найдутся те, кто не поймёт (или просто не захочет понимать в погоне за "оптимизацией") ни одного вашего слова и будет смотреть только на код.

DeimoS
20.10.2014, 16:29
А теперь встряну я :hi:

По поводу OnPlayerUpdate. Он действительно может вызываться всего пару раз за секунду в случае, когда игрок совсем не двигается. Достаточно просто встать на месте, перестать двигать камеру и всё, клиент практически перестанет отсылать данные об игроке, ибо новых данных нет. Но тут ещё всё зависит не только от активности самого игрока, но и от настроек в server.cfg.
Но даже если бы он обновлялся 25 раз за секунду постоянно (пока игрок не свернёт игру). Вероятность того, что между обновлением OnPlayerUpdate и вызовом таймера вклинится какой-то другой коллбэк, в котором идёт проверка на АФК, довольно велика. И будет ложное срабатывание.

Люди ещё с времён 0.2x, когда добавили OnPlayerUpdate, сделали адекватную реализацию отслеживания АФК и какой смысл изобретать велосипед по новой? Особенно если этот велосипед гораздо хуже предыдущего.

new pl_afk_time[MAX_PLAYERS];

public OnPlayerUpdate(playerid)
{
pl_afk_time[playerid] = -1;
}

public OnGameModeInit()
{
SetTimer("UpdateAfkTime", 1000, true);
}

forward UpdateAfkTime();
public UpdateAfkTime()
{
for(new i = GetMaxPlayers()-1; i != -1; i--)
{
if(!IsPlayerConnected(i)) continue;
pl_afk_time[i]++;
if(pl_afk_time[i] > 1)
{
printf("Игрок с ID %d находится в AFK [%d секунд]", i, pl_afk_time[i]);
}
}
}


new pl_afk_time[MAX_PLAYERS char];

public OnPlayerUpdate(playerid)
{
pl_afk_time{playerid} = 0;
}

public OnGameModeInit()
{
SetTimer("UpdateAfkTime", 1000, true);
}

forward UpdateAfkTime();
public UpdateAfkTime()
{
for(new i = GetMaxPlayers()-1; i != -1; i--)
{
if(!IsPlayerConnected(i)) continue;
if(pl_afk_time{i} < 2) pl_afk_time{i}++;
}
}

if(pl_afk_time{i} == 2) print("Игрок в AFK");

Всё. Осталось лишь чуть подкорректировать время в UpdateAfkTime, через которое игрок считается неактивным и система будет работать как часы

Dima_Tushin
05.06.2017, 13:00
А теперь встряну я :hi:

По поводу OnPlayerUpdate. Он действительно может вызываться всего пару раз за секунду в случае, когда игрок совсем не двигается. Достаточно просто встать на месте, перестать двигать камеру и всё, клиент практически перестанет отсылать данные об игроке, ибо новых данных нет. Но тут ещё всё зависит не только от активности самого игрока, но и от настроек в server.cfg.
Но даже если бы он обновлялся 25 раз за секунду постоянно (пока игрок не свернёт игру). Вероятность того, что между обновлением OnPlayerUpdate и вызовом таймера вклинится какой-то другой коллбэк, в котором идёт проверка на АФК, довольно велика. И будет ложное срабатывание.

Люди ещё с времён 0.2x, когда добавили OnPlayerUpdate, сделали адекватную реализацию отслеживания АФК и какой смысл изобретать велосипед по новой? Особенно если этот велосипед гораздо хуже предыдущего.

new pl_afk_time[MAX_PLAYERS];

public OnPlayerUpdate(playerid)
{
pl_afk_time[playerid] = -1;
}

public OnGameModeInit()
{
SetTimer("UpdateAfkTime", 1000, true);
}

forward UpdateAfkTime();
public UpdateAfkTime()
{
for(new i = GetMaxPlayers()-1; i != -1; i--)
{
if(!IsPlayerConnected(i)) continue;
pl_afk_time[i]++;
if(pl_afk_time[i] > 1)
{
printf("Игрок с ID %d находится в AFK [%d секунд]", i, pl_afk_time[i]);
}
}
}


new pl_afk_time[MAX_PLAYERS char];

public OnPlayerUpdate(playerid)
{
pl_afk_time{playerid} = 0;
}

public OnGameModeInit()
{
SetTimer("UpdateAfkTime", 1000, true);
}

forward UpdateAfkTime();
public UpdateAfkTime()
{
for(new i = GetMaxPlayers()-1; i != -1; i--)
{
if(!IsPlayerConnected(i)) continue;
if(pl_afk_time{i} < 2) pl_afk_time{i}++;
}
}

if(pl_afk_time{i} == 2) print("Игрок в AFK");

Всё. Осталось лишь чуть подкорректировать время в UpdateAfkTime, через которое игрок считается неактивным и система будет работать как часы

Взял себе спасибо.