[Tutorial] Optimizacion de cуdigo.
#1

- Optimizacion de cуdigo -
Hola, primero que nada me presento soy nuevo en esta comunidad, mas no en el lenguaje, por lo quiero ayudar a los que lo necesiten, no soy un experto pero tampoco soy nuevo, si necesitan ayuda con test o alguna funciуn problema con gusto podre ayudarles si tengo tiempo libre.

- Condicionales -
La optimizacion de cуdigo, como su nombre lo dice podremos agilizar la codificacion y que el servidor corra con el menos lag posible, con esto me refiero a cuando creamos un script, hay muchas maneras, pero no siempre las mas faciles de hacer son las mas eficientes. Nosotros debemos llamar siempre que sea posible al valor indicado y no buscar en los que esten disponibles, ejemplo:

pawn Код:
...
if(valor == 1) return 1;
if(valor == 2) return 2;
if(valor == 3) return 3;
...
Ese codigo seria valido, pero estaria mal optimizado, si recordamos que la sentencia "if" va bajando hasta encontrar el valor dado, si es uno, si es dos, si es tres.

pawn Код:
...
switch(valor)
{
    case 1: return 1;
    case 2: return 2;
    case 3: return 3;
}
...
Ese codigo estaria mas optimizado, ya que no busca entre los valores, si no va directamente a cual es. si es tres va hacia el 3, en cambio "if" empieza desde 1 hasta llegar al 3.

Aun que bien los dos son igualmente menos optimizados ya que al ser un valor entero y debemos regresar el mismo valor podriamos hacer simplemente:

pawn Код:
return valor;
En nuestro caso ese seria el mas efectivo de todos.

Los condicionales "if" deben ser usados en lo mнnimo posible cuando existan casos asн, ya que mucha gente no sabe de esto, usa "if" en casi todos los casos, muchas veces podemos optimizar con switch en las callbacks y ni siquiera lo sabemos, un ejemplo seria:
pawn Код:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    if(dialogid == DIALOGO_UNO)
        return funcion(...);
    if(dialogid == DIALOGO_DOS)
        return funcion(...);
    if(dialogid == DIALOGO_TRES)
        return funcion(...);
    return 1;
}
La mayoria de la gente hace esto y es lo peor que se puede hacer, por que muchas veces tenemos cientos de dialogos y los condicionales tendran que buscar uno por uno, imaginen si tenemos mas de mil dialogos y se llama al dialogo mil de esta forma, mil comprobaciones tendra que hacer el servidor, eso es un tanto lento para el.
pawn Код:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    switch(dialogid)
    {
        case DIALOGO_UNO: funcion(...);
        case DIALOGO_DOS: funcion(...);
        case DIALOGO_TRES: funcion(...);
    }
    return 1;
}
Esta forma seria mucho mas eficiente, ya que aun que tengamos diez mil dialogos y se llame al ultimo, el switch siempre enviara hacia el dialogo llamado, es mejor buscar en un libro por el indice y no pagina por pagina.

En muchas callbacks podemos aplicar switch, por ejemplo en numeros estaticos (como en OnPlayerPickUp cuando tenemos pickups que nunca se destruyen o respawnean o se crean mas), este tema de condicionales es muy amplio asi que lo acabare despues.

- Bucles -
Los bucles son muy importantes en la programacion, a todos nos daria flojera la comprobacion de uno por uno, repetir la misma funcion haciendo copy paste, los bucles pueden congelar nuestro servidor por segundos si se hace uno muy largo, por ejemplo:
pawn Код:
for(new x=0;x<9999999999;x++) {}
Un bucle asi congelaria un servidor dependiendo de los recursos donde este alojado, lo mejor es hacerlos lo mas corto posible, a que me refiero con esto, muchas personas cuando no hay parametro "playerid" en una callback lo que hacen es:
pawn Код:
for(new playerid=0;playerid<MAX_PLAYERS;playerid++)
    funcion(playerid,...);
Esto hace un bucle de 500 repeticiones, la mayoria de la gente no tiene ni cien jugadores en su servidor por lo que podriamos re-definir la constante MAX_PLAYERS:
pawn Код:
#undef MAX_PLAYERS
#define MAX_PLAYERS 100
Eso dejaria a el bucle con 100 repeticiones, pero muchas veces ni esos estan conectados y si la funcion que conlleva al bucle es muy grande tardaria mas tiempo, por eso podemos poner condicionales como si el jugador esta conectado o no es un bot, aun que en estos casos el uso de iteradores (como foreach <******>) son la mejor opcion ya que solo hacen la repeticion para los jugadores conectados unicamente sin condicionales por lo que son mas rapidos.

Los bucles hay que manejarlos con cuidado por razones dichas anteriormente, aun que aveces no son necesarios si queremos repetir una funcion menos de diez veces, es mejor hacer copy paste, ya que la creacion de un bucle mas la funcion tomaria mas tiempo de ejecucion.

- Comandos -
Mucha gente y como ya hablamos anteriormente, se dejan llevar usando condicionales ("if") en OnPlayerCommandText, y como ya dijimos esto es un error muy grande por que muchos pueden tener miles de comandos y tendria que verificar uno por uno, lo correcto seria usar un procesador de comandos, a que me refiero con esto; un procesador de comandos es como el switch comparado con el if, ya que llama directamente al comando que se tecleo, sin buscar entre los demas, por eso es mucho mas rapido (cuando se tienen demasiados comandos), los mas conocidos son zcmd y y_commands. en este tema no hay mucho que abordar ya que la mayor parte es sobre las condicionales que ya mencionamos.

- Timers y OnPlayerUpdate -
Muchas personas piensan que el uso de estos dos, nos dara un gran lag, sin embargo al usarlos correctamente no da lag alguno, muchas veces creamos demasiados timers (hasta 1 por jugador o mas), algo que seria incorrecto por que, los temporizadores por alguna razon comienzan a dar lag al tener muchos, aun que no lo crean con tener un timer es mas que suficiente para todo el servidor, en ese timer se llamaria cada segundo o medio segundo y ahi asignarian las funciones que se requieran tanto para el servidor como usuarios, usando foreach seria aun mejor:
pawn Код:
public timer()
{
    funcion(...);
    foreach(new playerid : Player)
    {
        funcion(playerid,...);
    }
}
Con esto seria mas que suficiente para tener una actualizacion, no necesitamos crear timers nuevos, si hacemos el ejemplo anterior con un tiempo base (como medio segundo o uno completo) podriamos crear variables que se sumen ahi mismo y llamar a x funcion cuando esta se complete y se regresa el valor a 0, es mas sencillo de lo que suena pero no me adentrare mucho en los timers ya que es un tema muy extenso.

La callback OnPlayerUpdate si da lag si no la sabes usar, para comenzar esta callback es llamada cuando se actualiza cliente-servidor, que quiero decir, que el servidor esta en constante actualizacion (vease server.cfg>streamer/onfoot/weapon_rate) que son 40 milisegundos por defecto, y eso es por cada cliente, si metemos algo muy pesado en esa callback por ejemplo escritura/lectura de archivos con dini guardaria datos cada 40 milisegundos, y si dini tarda 2 milisegundos por archivo, bastarian al menos 10 jugadores para que comienze el lag, y al menos 20 para que sea insoportable, ahora que comprendimos como es el funcionamiento de esa callback podemos hacer un buen uso de ella, debemos meter el minimo de funciones ahi e incluso si es posible dejarla vacia.

- Codificacion -
Practicamente esto no es para acelerar la velocidad de procesamiento de nuestro servidor, pero si es bueno que aprendamos primeramente, la tabulacion, mucha gente no tabula o no sabe como hacerlo, la tabulacion es muy importante ya que nos ayuda a localizar facilmente que funciones estan dentro de otras funciones, tambien le da estetica a nuestro codigo:
pawn Код:
public OnGameModeInit()
{
    new mode = 1;
    if(mode == 1)
        funcion(...);
    return 1;
}
Un codigo bien alineado siempre sera atractivo.

La ortografia; somos programadores, lo que significa que el uso de una mayuscula puede costarnos un error en el programa, lo mejor es que aprendamos bien el nombre de las funciones y escribamos correctamente, tambien le da estetica, no me refiero a escribir perfecto pero por lo menos no hacerse notar que es un idiota:
pawn Код:
printg("ola ke onda? soy re trol");
Debe tener serios problemas con los libros, cuando una persona escribe bien, mas ganas dan de ver sus trabajos.

Arreglos, un arreglo o array son muchas variables comprendidas en una, a que me refiero:
pawn Код:
new hola[100];
Ahi tendriamos 100 variables, no hay necesidad de repetir lo mismo 100 veces.

Espanglish, a que me refiero con esto, si somos hispanohablantes que se haga notar, muchos al crear una funcion o variable hacen esto:
pawn Код:
stock IsPlayerInAquellaZona(...)
Por favor, si van a programar que sea en un lenguaje, yo se que las funciones nativas se van a quedar en ingles pero si hacen otras que sea en espaсol completo o ingles completo.

- Otras callbacks -
Las callbacks son llamadas cuando pasan eventos dentro del servidor, se presiona una tecla, se sube a un auto, muere, entre otras, debemos saber cuales se llaman mas seguido en nuestro servidor y optimizarlas lo mas posible, por ejemplo en un servidor deathmach, la callback que probablemente es llamada mas seguido (sin contar OnPlayerUpdate) es OnPlayerDeath, en este caso no podemos estar metiendo codigo basura o lento ya que nos re-lentiza nuestro servidor.

- Funciones pesadas -
Aveces tenemos funciones que pueden ir lento, como pueden tener bucles o guardado en archivos, por lo que tenemos que llamarlas cada vez que sea necesario, ya que si llamamos constantemente pueden causar lag.

- Tiempos -
Usted puede tomar el tiempo de cuanto tarda una funcion en procesarse, haciendo un bucle y obteniendo el tiempo con GetTickCount (devuelve en milisegundos), asi podra saber que tanto tarda.

Aun falta mucho por explicar, y no esta completo, tratare de terminarlo en la brevedad posible, cabe aclarar que el tiempo del que hablo no llega ni al milisegundo (o algunas veces si) pero si usted optimiza su codigo bien puede tener una velocidad de procesamiento mejor, y menos lag, recordando que el servidor corre en un hilo (debe acabar una funcion para empezar otra) entonces si las funciones tardan menos respondera mas rapido el servidor.

Cualquier duda comentario queja donativo pregunta donativo por paypal es bienvenid@.
Reply
#2

Estб buena, aunque es optimizaciуn bбsica obviamente.. Hay optimizaciуn mucho mбs potente: https://sampforum.blast.hk/showthread.php?tid=57018

Te doy rep igual, le va a servir a varios.
Reply
#3

Efectivamente como dices es basica, pero estube mirando la mayoria de los codigos y y es lo que mas se necesita, aun no lo termino, aun que cuando siga sera basandome en el tutorial de ******.
Reply
#4

Trata de poner lo de states machines, le va a servir a varios.
Reply
#5

Muy buйn tutorial pero usted tiene un error de cуdigo con las sentencias if.

pawn Код:
if(valor == 1) return 1;
else if(valor == 2) return 2;
else if(valor == 3) return 3;
Bueno tambiйn definir las variables globales con static en vйz de new optimiza mбs el acceso a la memoria. Definir funciones con static o simplemente sin el prefijo stock optimiza la llamada a la funciуn.

El buйn uso de los operadores pueden optimizar aъn mбs nuestro cуdigo:

pawn Код:
if(!Variable == 1)
Error la forma correcta seria:

pawn Код:
if(Variable != 1)
Muchos crean funciones para devolver un valor segъn sea el valor de la variable comparada.

pawn Код:
stock Comaparar(Variable)
{
   switch(Variable)
   {
        case 0: String = "caso de ser 0";
        case 1: String = "caso de ser 1";
   }
   return String;
}
La forma correcta seria:

pawn Код:
Variable?("En caso de ser 1"):("En caso de ser 0");
PD: Recuerde que tambiйn crear macros de funciones mediante #define es mucho mбs rбpido que crear una funciуn por la razуn que #define es llamado por el pre-procesador.

Un saludo.
Reply
#6

Tambiйn podrнas poner lo de usar variables booleanas cuando se tengan variables con dos valores a usarse, ya que consumen menos memoria dinбmica las booleanas (creo que la diferencia es de 31 bits).
Reply
#7

Mi recomendacion, antes de realizar optimizaciones de este tipo, es primero revisar la estructura del codigo. Muchas veces, se concentran tanto en optimizaciones menores, que se pierden de optimizar una estructura (cosa que en la mayoria de los casos da mejores resultados).
  • Ciclos, loops o bucles:
    Resulta muy poco practico el metodo que propones. Es mucho mas recomendable utilizar foreach o en su defecto, esta estructura:
    pawn Код:
    for(new i, j=GetMaxPlayers(); i<j; i++)
  • Temporizadores (timers):
    En realidad, tu teoria no es del todo correcta, si sobrecargas demasiado cualquier callback, acabara durando demasiado tiempo. Debes recordar que el servidor SA-MP es de 1 solo hilo, es decir ejecuta 1 accion a la vez. Si tu temporizador tarda 50ms en ejecutarse, durante esos 50ms el servidor se "congelara" para los jugadores. Se sugiere utilizar y_timers o si es posible (recomendado) el plugin fixes2, el cual mejora las funciones nativas y ademas provee otras las cuales permiten un mayor control sobre temporizadores.

    Cualquier cosa avisame y puedo ayudarte.


    Quote:
    Originally Posted by DeadSkyTkb
    Посмотреть сообщение
    Tambiйn podrнas poner lo de usar variables booleanas cuando se tengan variables con dos valores a usarse, ya que consumen menos memoria dinбmica las booleanas (creo que la diferencia es de 31 bits).
    Error, pawn es totalmente typeless o lo que se traduce a libre de tipos, los tags no cambian absolutamente nada. Por lo cual, utilizar 'bool:' o no delante de una variable no afectara su performance, ni el espacio que esta ocupa.
Reply
#8

@ 0xFFFFFF Buen Tutorial .

@ oOFotherOo una duda sobre la forma correcta de comparar, como se coloca en un if o como ?
quedaria asi'
pawn Код:
static Variable[MAX_PLAYERS];
if(Variable[playerid]?("En caso de ser 1"):("En caso de ser 0")) {
    //Funcion
}
@ the_chaoz sobre el bucle, te equivocaste oes asi?, pusiste 2 J for(new i, j=GetMaxPlayers(); i<j; i++)

Saludos.
Reply
#9

Quote:
Originally Posted by OTACON
Посмотреть сообщение
[COLOR="DarkOrchid"]@ oOFotherOo una duda sobre la forma correcta de comparar, como se coloca en un if o como ?
quedaria asi'
pawn Код:
static Variable[MAX_PLAYERS];
if(Variable[playerid]?("En caso de ser 1"):("En caso de ser 0")) {
    //Funcion
}
Es el operador ternario
ejemplo:
pawn Код:
new
    bool:var = true,
    aux;

//dentro de algun callback o funcion
if(var == true)
    aux = 104;
else
    aux = 56;

//El if-else anterior equivale a:
aux = ((var == true) ? (104) : (56));
Este operador solo deberia utilizarse cuando realmente no hay opcion, ya que quita claridad al codigo y no es mejor que utilizar if en terminos de performance.

Quote:
Originally Posted by OTACON
Посмотреть сообщение
@ the_chaoz sobre el bucle, te equivocaste oes asi?, pusiste 2 J for(new i, j=GetMaxPlayers(); i<j; i++)

Saludos.
El codigo es asi y esta bien. Lo que esa linea hace es crear 2 variables ('j' e 'i'); a 'j' le asigna el valor que retorna la funcion 'GetMaxPlayers()' (por lo que ya tenemos i=0; j=GetMaxPlayers()); luego aumenta 1 mientras que i sea menor al valor de j. Se crea la variable auxiliar j para evitar llamar a la funcion 'GetMaxPlayers()' en cada iteracion del for y aumentar la performance.
Reply
#10

Quote:
Originally Posted by the_chaoz
Посмотреть сообщение
Es el operador ternario
ejemplo:
pawn Код:
new
    bool:var = true,
    aux;

//dentro de algun callback o funcion
if(var == true)
    aux = 104;
else
    aux = 56;

//El if-else anterior equivale a:
aux = ((var == true) ? (104) : (56));
Este operador solo deberia utilizarse cuando realmente no hay opcion, ya que quita claridad al codigo y no es mejor que utilizar if en terminos de performance.

El codigo es asi y esta bien. Lo que esa linea hace es crear 2 variables ('j' e 'i'); a 'j' le asigna el valor que retorna la funcion 'GetMaxPlayers()' (por lo que ya tenemos i=0; j=GetMaxPlayers()); luego aumenta 1 mientras que i sea menor al valor de j. Se crea la variable auxiliar j para evitar llamar a la funcion 'GetMaxPlayers()' en cada iteracion del for y aumentar la performance.
ah ok, justamente por eso tenia esa duda me hizo confundi.

bien, ahora me quedo claro, pregunte por ke se lo veia a algunos ke lo utilizaban asi pense ke se ekivocaban, ahora me quedo claro.

Muchas gracias por aclaramedas a las dudas .
Saludos.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)