Pawn. Оптимизация циклов игроков
Замутил тестик всех способов создания циклов MAX_PLAYERS
с использованием OnPlayerConnect
и OnPlayerDisconnect
(ведь тики на них тоже тратятся).
Тест №1🔗︎
В тесте ID'ы подключающихся различны на 10, поэтому способы, которые запоминают все имеющиеся ID'ы будут лидировать.
Код тут:Спойлер
#include <..\compiler\includes\a_samp>
#include "foreach"
main(){}
#undef MAX_PLAYERS
#define MAX_PLAYERS 200
#define PLAYER_CONNECTING 10
#define PLAYER_DISCONNECTING 10
//
#define foreach_step(%0) for(new p_i,%0 = MAX_ONLINE_PLAYERS[p_i]; (%0 = MAX_ONLINE_PLAYERS[p_i]) != INVALID_PLAYER_ID; p_i++)
new MAX_ONLINE_PLAYERS[MAX_PLAYERS] = {INVALID_PLAYER_ID, ...};
//
#define GetPlayerLastID() players_lastID
new players_lastID = 0;
forward plcount_OnPlayerConnect(playerid);
public plcount_OnPlayerConnect(playerid)
{
if(players_lastID < playerid) players_lastID = playerid;
return 1;
}
forward plcount_OnPlayerDisconnect(playerid,reason);
public plcount_OnPlayerDisconnect(playerid,reason)
{
#pragma unused reason
if(players_lastID == playerid && playerid != 0)
{
do players_lastID--;
while((IsPlayerNPC(playerid) || (!IsPlayerConnected(players_lastID))) && (players_lastID > 0));
}
return 1;
}
//
// PLIDs
new PLIDs[MAX_PLAYERS] = {-1,...};
new MaxPlayers = 0;
forward plids_OnPlayerConnect(playerid);
public plids_OnPlayerConnect(playerid)
{
PLIDs[MaxPlayers] = playerid;
MaxPlayers++;
return 1;
}
forward plids_OnPlayerDisconnect(playerid,reason);
public plids_OnPlayerDisconnect(playerid,reason)
{
for(new i=0;i<MaxPlayers;i++)
{
if(PLIDs[i] == playerid)
{
MaxPlayers--;
PLIDs[i] = PLIDs[MaxPlayers];
PLIDs[MaxPlayers] = -1;
break;
}
}
return 1;
}
//
public OnGameModeInit()
{
// 200 слотов
// IsPlayerConnected
new count = GetTickCount();
for(new j=0;j<10000;j++)
{
for(new i=0;i<PLAYER_CONNECTING;i++)
_OnPlayerConnect(i*10);
for( new i; i < 200; i ++ )
{
if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
for(new i=0;i<PLAYER_CONNECTING;i++)
_OnPlayerDisconnect(i*10,0);
}
printf("IsPlayerConnected: %d", GetTickCount() - count);
// GetMaxPlayers
count = GetTickCount();
for(new j=0;j<10000;j++)
{
for(new i=0;i<PLAYER_CONNECTING;i++)
_OnPlayerConnect(i*10);
for( new i=GetMaxPlayers()-1 ; i>=0 ; --i )
{
if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
for(new i=0;i<PLAYER_CONNECTING;i++)
_OnPlayerDisconnect(i*10,0);
}
printf("GetMaxPlayers: %d", GetTickCount() - count);
// GetPlayerLastID
count = GetTickCount();
for(new j=0;j<10000;j++)
{
for(new i=0;i<PLAYER_CONNECTING;i++)
plcount_OnPlayerConnect(i*10);
for( new i=0 ; i <= GetPlayerLastID() ; i++ )
{
if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
for(new i=0;i<PLAYER_CONNECTING;i++)
plcount_OnPlayerDisconnect(i*10,0);
}
printf("GetPlayerLastID: %d", GetTickCount() - count);
// PLIDs
count = GetTickCount();
for(new j=0;j<10000;j++)
{
for(new i=0;i<PLAYER_CONNECTING;i++)
plids_OnPlayerConnect(i*10);
for( new i=0 ; i < MaxPlayers ; i++ )
{
if(!IsPlayerConnected(PLIDs[i]) || IsPlayerNPC(PLIDs[i])) continue;
}
for(new i=0;i<PLAYER_DISCONNECTING;i++)
plids_OnPlayerDisconnect(i*10,0);
}
printf("PLID: %d", GetTickCount() - count);
// foreach
count = GetTickCount();
for(new j=0;j<10000;j++)
{
for(new i=0;i<PLAYER_CONNECTING;i++)
Iter_Add(Player,i*10);
foreach(Player, i)
{
if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
for(new i=0;i<PLAYER_DISCONNECTING;i++)
Iter_Remove(Player,i*10);
}
printf("foreach: %d", GetTickCount() - count);
// foreach by Stepashka
count = GetTickCount();
for(new j=0;j<10000;j++)
{
for(new i=0;i<PLAYER_CONNECTING;i++)
step_OnPlayerConnect(i*10);
foreach_step(i)
{
if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
for(new i=0;i<PLAYER_DISCONNECTING;i++)
step_OnPlayerDisconnect(i*10,0);
}
printf("foreach_step: %d", GetTickCount() - count);
return 1;
}
forward _OnPlayerConnect(playerid);
public _OnPlayerConnect(playerid)
{
return 1;
}
forward _OnPlayerDisconnect(playerid,reason);
public _OnPlayerDisconnect(playerid,reason)
{
return 1;
}
forward step_OnPlayerConnect(playerid);
public step_OnPlayerConnect(playerid)
{
for ( new i; i < MAX_PLAYERS; i++)
{
if ( INVALID_PLAYER_ID == MAX_ONLINE_PLAYERS[i])
{
MAX_ONLINE_PLAYERS[i] = playerid;
break;
}
}
//...
return 1;
}
forward step_OnPlayerDisconnect(playerid, reason);
public step_OnPlayerDisconnect(playerid, reason)
{
for ( new i, bool:foundPlayer = false; i < MAX_PLAYERS; i++)
{
if ( playerid == MAX_ONLINE_PLAYERS[i] || true == foundPlayer)
{
if ( i+1 < MAX_PLAYERS)
{
if ( (MAX_ONLINE_PLAYERS[i] = MAX_ONLINE_PLAYERS[i+1]) == INVALID_PLAYER_ID)
{
break;
}
foundPlayer = true;
}
else
{
MAX_ONLINE_PLAYERS[i] = INVALID_PLAYER_ID;
}
}
}
//...
return 1;
}
Результаты:
- IsPlayerConnected: 509
- GetMaxPlayers: 503
- GetPlayerLastID: 591 (мною модифицированный способ от Alex009)
- PLID: 187 (предложенный вариант)
- foreach: 246 (foreach от Y_Less'a)
- foreach_step: 647 (foreach который опубликовал степашка)
Тест №2🔗︎
Дальше я решил количество подключений и отключений привести к более реальному количеству.
Код тут:Спойлер
#include <..\compiler\includes\a_samp>
#include "foreach"
main(){}
#undef MAX_PLAYERS
#define MAX_PLAYERS 200
#define PLAYER_CONNECTING 50
#define PLAYER_DISCONNECTING 50
//
#define foreach_step(%0) for(new p_i,%0 = MAX_ONLINE_PLAYERS[p_i]; (%0 = MAX_ONLINE_PLAYERS[p_i]) != INVALID_PLAYER_ID; p_i++)
new MAX_ONLINE_PLAYERS[MAX_PLAYERS] = {INVALID_PLAYER_ID, ...};
//
new
list_player_IDs[ MAX_PLAYERS ] = { -1, ... },
maxPlayers = 0;
#define forscan(%1) for( new __idx = 0, %1 = 0; __idx < maxPlayers; %1 = list_player_IDs[ ++__idx ] )
stock forscan_connect( playerid )
{
list_player_IDs[ maxPlayers ] = playerid;
maxPlayers++;
}
stock forscan_disconnect( playerid, reason )
{
for ( new i = 0; i < maxPlayers; i++ )
{
if ( list_player_IDs[ i ] == playerid )
{
maxPlayers--;
list_player_IDs[ i ] = list_player_IDs[ maxPlayers ];
list_player_IDs[ maxPlayers ] = -1;
break;
}
}
}
//
#define GetPlayerLastID() players_lastID
new players_lastID = -1;
forward plcount_OnPlayerConnect(playerid);
public plcount_OnPlayerConnect(playerid)
{
if(players_lastID < playerid) players_lastID = playerid;
return 1;
}
forward plcount_OnPlayerDisconnect(playerid,reason);
public plcount_OnPlayerDisconnect(playerid,reason)
{
#pragma unused reason
if(players_lastID == playerid && playerid != 0)
{
do players_lastID--;
while((IsPlayerNPC(playerid) || (!IsPlayerConnected(players_lastID))) && (players_lastID > 0));
}
return 1;
}
//
// PLIDs
new PLIDs[MAX_PLAYERS] = {-1,...};
new MaxPlayers = 0;
forward plids_OnPlayerConnect(playerid);
public plids_OnPlayerConnect(playerid)
{
PLIDs[MaxPlayers] = playerid;
MaxPlayers++;
return 1;
}
forward plids_OnPlayerDisconnect(playerid,reason);
public plids_OnPlayerDisconnect(playerid,reason)
{
for(new i=0;i<MaxPlayers;i++)
{
if(PLIDs[i] == playerid)
{
MaxPlayers--;
PLIDs[i] = PLIDs[MaxPlayers];
PLIDs[MaxPlayers] = -1;
break;
}
}
return 1;
}
//
public OnGameModeInit()
{
// 200 слотов
// IsPlayerConnected
new count = GetTickCount();
for(new i=0;i<PLAYER_CONNECTING;i++)
_OnPlayerConnect(i*10);
for(new j=0;j<10000;j++)
{
for( new i; i < 200; i ++ )
{
if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
}
for(new i=0;i<PLAYER_CONNECTING;i++)
_OnPlayerDisconnect(i*10,0);
printf("IsPlayerConnected: %d", GetTickCount() - count);
// GetMaxPlayers
count = GetTickCount();
for(new i=0;i<PLAYER_CONNECTING;i++)
_OnPlayerConnect(i*10);
for(new j=0;j<10000;j++)
{
for( new i=GetMaxPlayers()-1 ; i>=0 ; --i )
{
if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
}
for(new i=0;i<PLAYER_CONNECTING;i++)
_OnPlayerDisconnect(i*10,0);
printf("GetMaxPlayers: %d", GetTickCount() - count);
// GetPlayerLastID
count = GetTickCount();
for(new i=0;i<PLAYER_CONNECTING;i++)
plcount_OnPlayerConnect(i*10);
for(new j=0;j<10000;j++)
{
for( new i=0 ; i <= GetPlayerLastID() ; i++ )
{
if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
}
for(new i=0;i<PLAYER_CONNECTING;i++)
plcount_OnPlayerDisconnect(i*10,0);
printf("GetPlayerLastID: %d", GetTickCount() - count);
// PLIDs
count = GetTickCount();
for(new i=0;i<PLAYER_CONNECTING;i++)
plids_OnPlayerConnect(i*10);
for(new j=0;j<10000;j++)
{
for( new i=0,playerid ; i < MaxPlayers ; i++ )
{
playerid = PLIDs[i];
}
}
for(new i=0;i<PLAYER_DISCONNECTING;i++)
plids_OnPlayerDisconnect(i*10,0);
printf("PLID: %d", GetTickCount() - count);
// foreach
count = GetTickCount();
for(new i=0;i<PLAYER_CONNECTING;i++)
Iter_Add(Player,i*10);
for(new j=0;j<10000;j++)
{
foreach(Player, i)
{
//if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
}
for(new i=0;i<PLAYER_DISCONNECTING;i++)
Iter_Remove(Player,i*10);
printf("foreach: %d", GetTickCount() - count);
// foreach by Stepashka
count = GetTickCount();
for(new i=0;i<PLAYER_CONNECTING;i++)
step_OnPlayerConnect(i*10);
for(new j=0;j<10000;j++)
{
foreach_step(i)
{
//if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
}
for(new i=0;i<PLAYER_DISCONNECTING;i++)
step_OnPlayerDisconnect(i*10,0);
printf("foreach_step: %d", GetTickCount() - count);
// forscan
count = GetTickCount();
for(new i=0;i<PLAYER_CONNECTING;i++)
forscan_connect( i*10 );
for(new j=0;j<10000;j++)
{
forscan(i)
{
//if(!IsPlayerConnected(i) || IsPlayerNPC(i)) continue;
}
}
for(new i=0;i<PLAYER_DISCONNECTING;i++)
forscan_disconnect( i*10, 0 );
printf("forscan: %d", GetTickCount() - count);
return 1;
}
forward _OnPlayerConnect(playerid);
public _OnPlayerConnect(playerid)
{
return 1;
}
forward _OnPlayerDisconnect(playerid,reason);
public _OnPlayerDisconnect(playerid,reason)
{
return 1;
}
forward step_OnPlayerConnect(playerid);
public step_OnPlayerConnect(playerid)
{
for ( new i; i < MAX_PLAYERS; i++)
{
if ( INVALID_PLAYER_ID == MAX_ONLINE_PLAYERS[i])
{
MAX_ONLINE_PLAYERS[i] = playerid;
break;
}
}
//...
return 1;
}
forward step_OnPlayerDisconnect(playerid, reason);
public step_OnPlayerDisconnect(playerid, reason)
{
for ( new i, bool:foundPlayer = false; i < MAX_PLAYERS; i++)
{
if ( playerid == MAX_ONLINE_PLAYERS[i] || true == foundPlayer)
{
if ( i+1 < MAX_PLAYERS)
{
if ( (MAX_ONLINE_PLAYERS[i] = MAX_ONLINE_PLAYERS[i+1]) == INVALID_PLAYER_ID)
{
break;
}
foundPlayer = true;
}
else
{
MAX_ONLINE_PLAYERS[i] = INVALID_PLAYER_ID;
}
}
}
//...
return 1;
}
Результаты:
- IsPlayerConnected: 888
- GetMaxPlayers: 304
- GetPlayerLastID: 2169 (мною модифицированный способ от Alex009)
- PLID: 145 (предложенный вариант)
- foreach: 123 (foreach от Y_Less'a)
- foreach_step: 134 (foreach который опубликовал степашка)
- forscan: 168 (forscan от Jester(более удобный PLID))
Тут результаты куда более приятнее. Забавно, что способ с GetPlayerLastID
стал работать в несколько раз медленнее.
Собственно я делаю выбор за foreach Y_Less'а - быстро, удобно, функционально.