JeuWeb - Crée ton jeu par navigateur
Calcul de tour qui passe maaaal - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Calcul de tour qui passe maaaal (/showthread.php?tid=3687)

Pages : 1 2


Calcul de tour qui passe maaaal - Feldoran - 18-02-2009

Salut à tous,

je travaille sur un jeu de gestion assez simple. Dans un principe classique de tour par tour. Donc les joueurs pendant la journée choisissent leurs actions (quelques UPDATES pas bien méchants), et c'est la nuit que le résultat de toutes ces actions est calculé.

Pour ce gros traitement de calcul de tour, le schéma est grosso modo le suivant:
1) 4 SELECT qui récupèrent des infos pour les mettre dans des Arrays à réutiliser plus tard (données relatives aux actions que les joueurs ont pu demander, surtout).

2) 1 gros SELECT qui récupère tous les comptes, puis je boucle là dessus

3) Au sein de la boucle sur (2), je fais juste des calculs mathématiques simples et je termine avec un UPDATE qui met à jour les données du compte... donc un update par compte considéré


Au bout d'une semaine d'inactivité, les comptes sont mis en Etat=0, considérés comme en repos, et ne rentrent pas dans la grosse boucle. Ce qui fait qu'en conditions réelles, je ne pense pas atteindre des masses gigantesques de joueurs à calculer. Mais pour mes tests de montée en charge, j'ai cherché à aller loin, il me parait utile de connaître les limites de mon serveur.

Bon, en local avec Xampp, même si le traitement peut parfois être un peu long, ça passe avec plus de 200.000 comptes.
Sur un hébergement basique de Online.net, ça passe jusqu'à 50.000 comptes, mais au delà ça sèche.
Chez OVH sur un 90PLAN, ça plante très vite, impossible de calculer 10.000 comptes (la requête numéro 2 passe tres bien, d'autant qu'elle est indexée, mais pdt le bouclage, patatra).

Mon but, tout de même, est de ne lancer ce traitement qu'une fois par jour, en heure creuse (3 ou 4h du matin).

Alors ok, je suis bien conscient qu'il suffit pas de lancer un jeu pour y retrouver 10.000 joueurs en 2 semaines, la question n'est pas là. J'aimerais savoir comment vous procédez pour effectuer ce genre de gros traitement sans mettre à genoux les serveurs.
J'ai tâché d'optimiser pas mal, mais au bout d'un moment, la grosse boucle me paraît tout de même inévitable...

Merci d'avance,
a++
Feldo


RE: Calcul de tour qui passe maaaal - Ter Rowan - 18-02-2009

salut

je vais peut être dire de grosses bétises mais je me lance

si tes calculs (3) sont simples est ce que tu ne devrais pas faire directement les calculs via ta bdd

je vois deux possibilités :

1) réaliser directement une seule instruction update qui croisent les infos des étapes 1 et 2

2) avoir une table "temporaire" (ou de calcul) qui te permet de stocker des résultats intermédiaires de l'étape 1 (si elle est compliquée) puis de lancer une seule instruction update croisant les infos de l'étape 2 et de la table temporaire

ainsi, tu fais beaucoup moins de requêtes, donc d'appels donc du temps de gagner

maintenant ce serait surement mieux avec le code et les requetes pour que les cadors puissent faire une vraie analyse


RE: Calcul de tour qui passe maaaal - Mycroft - 18-02-2009

Je sais pas si c'est une stratégie viable, mais dans le mesure du possible, je pense que de plutôt boucler sur tous les comptes il vaut mieux faire des requête du style :

Pour un incrément automatique de 10 unité de money:
"UPDATE comptes SET money = '100' WHERE money = '90'"
"UPDATE comptes SET money = '90' WHERE money = '80'"
etc

Ca te permet de mettre à jour plus de lignes pour une seule requête. Au moins le nombre de requête reste constant que tu aies 1000 ou 10 000 joueurs.

Bon bien sûr c'est pas forcément faisable...


RE: Calcul de tour qui passe maaaal - Feldoran - 18-02-2009

Merci pour ta réponse, en fait même si les calculs sont simples (principalement additions et soustractions, il y en a quand même un paquet et ça serait ptet lourd à passer via la BDD. Je sais pas, j'ai pas vraiment étudié cette voie.
En fait, je crois que ça bloquerait au niveau des interactions entre joueurs. Certaines actions influent sur les autres joueurs, donc là ça devient chaud à gérer hors PHP.


Pour les requêtes, les 4 premières sont tres simples du genre:
Code :
SELECT qualite, niveau, libelle, modNotoriete, modPopularite, modSoutien, modFaveur, modCasseroles FROM evenement

Voici la numéro 2:
Code PHP :
<?php 
$sql
= 'SELECT idcompte, prenom, nom, sexe, idparti, idNouveauParti, notoriete, popularite, soutien, faveur, casseroles';
$sql.= ', declaration, declarationPrevue, ordre';
$sql.= ', lastconn';
$sql.= ', pouvoirType, pouvoirCible, appelType, appelCible';
$sql.= ', ciblagePouvDiffamation, ciblagePouvFilature, ciblagePouvPigeonnage, ciblagePouvAccusation, ciblagePouvAccident';
$sql.= ', appelType, ciblageAppelEspionnage, ciblageAppelFauxTemoin, ciblageAppelSabotage';
$sql.= ' FROM compte';
$sql.= ' WHERE etat > 0';
$result = executer_requete ($sql);

C'est donc avec ces infos que je calcule les modificateurs à appliquer... on gère la carrière d'un politicien donc ses actions et celles de ses adversaires influent sur sa popularité, sa notoriété, etc...

Et l'update en fin de boucle:
Code PHP :
<?php 
$sql_maj
= 'UPDATE compte SET';
$sql_maj.= ' notoriete = ' . $maj_notoriete;
$sql_maj.= ', popularite = ' . $maj_popularite;
$sql_maj.= ', soutien = ' . $maj_soutien;
$sql_maj.= ', faveur = ' . $maj_faveur;
$sql_maj.= ', casseroles = ' . $maj_casseroles;
if (isset(
$maj_etat)) $sql_maj.= ', etat = ' . $maj_etat;
$sql_maj.= ", declaration = '" . $ligne['declarationPrevue'] . "'";
$sql_maj.= ', declarationPrevue = null';
if (!(
is_null($maj_idparti))) $sql_maj.= ', idparti = ' . $maj_idparti;
$sql_maj.= ', idNouveauParti = null';
$sql_maj.= ', ordre = 0';
$sql_maj.= ', score = ' . $score;
$sql_maj.= ", crAction = '" . addslashes($maj_crAction) . "'";
$sql_maj.= ", crDivers = '" . addslashes($maj_crDivers) . "'";
if (
$maj_crPegre != '') $sql_maj.= ", crPegre = '" . addslashes($maj_crPegre) . "'";
if (
$maj_crPouvoir != '') $sql_maj.= ", crPouvoir = '" . addslashes($maj_crPouvoir) . "'";
if (
$maj_crEvA != null)
$sql_maj.= ", crEvA = '" . addslashes($maj_crEvA) . "'";
else
$sql_maj.= ", crEvA = null";
$sql_maj.= ' WHERE idcompte = ' . $ligne['idcompte'];
executer_requete($sql_maj);

(requêtes un poil simplifiées pour pas faire trop long, mais l'essence est là)
(18-02-2009, 01:13 PM)Mycroft a écrit : Je sais pas si c'est une stratégie viable, mais dans le mesure du possible, je pense que de plutôt boucler sur tous les comptes il vaut mieux faire des requête du style :

Pour un incrément automatique de 10 unité de money:
"UPDATE comptes SET money = '100' WHERE money = '90'"
"UPDATE comptes SET money = '90' WHERE money = '80'"
etc

Ca te permet de mettre à jour plus de lignes pour une seule requête. Au moins le nombre de requête reste constant que tu aies 1000 ou 10 000 joueurs.

Bon bien sûr c'est pas forcément faisable...

Bonne idée mais pas applicable dans mon cas, malheureusement. Les mises à jour sont vraiment spécifiques à chaque compte car il y a plusieurs sources de modifications des stats de perso: l'action du joueur, les évènements aléatoires et les coups fourrés des autres joueurs. Plus un peu de random.


RE: Calcul de tour qui passe maaaal - Allwise - 18-02-2009

Déjà, faudrait savoir si ça coince au niveau du nombre de requêtes ou au niveau du temps d'exécution du script.
Dans les deux cas, tu n'es pas obligé de tout mettre à jour en une seule exécution. Tu peux ajouter un champ "last_update" et, dans ta requête (2), tu ne sélectionnes que les enregistrements qui n'ont pas été mis à jour en comparant last_update à la date courante, et par paquet de x joueurs. Le x est à définir en fonction du nombre maximum de requêtes par heure sur le serveur, et en fonction du temps maximum d'exécution d'un script / du temps nécessaires pour traiter tes enregistrements.
Ainsi, tu peux échelonner l'exécution de ton script et répartir la charge sur une période plus longue. Et à chaque fois que le script est lancé, seuls les enregistrements concernés sont traités.


RE: Calcul de tour qui passe maaaal - Feldoran - 18-02-2009

Oui, j'essayais de trouver une manière d'échelonner mais c'est pas forcément évider de trouver en combien de morceaux découper ça.

Je ne savais pas que les hébergeurs limitaient en nb de requêtes par heure, est-ce qu'on connaît ces chiffres pour les hébergeurs principaux?
Sinon je me renseignerai auprès du support.


RE: Calcul de tour qui passe maaaal - wild-D - 18-02-2009

^^ en mutualisé tu as souvent plein de limitation
- temps execution
- RAM
- charge CPU
- et autre tambouille
chaque hebergeur à sa petite cuisine

balancer un update complet aussi rustre; sur un mutualisé tu vas dans le mur avec le nombre de joueurs croissant.


tu pourrais pas envisager "d'atomiser" tes mises à jour ?
- si t'as pas d'interaction directe entre les joueurs, un update à la première connexion journalière du joueur.
au lieu d'avoir un pic massif de charge pour effectuer ta mise à jour, tu répartis ça sur chaque connexion. Autre avantage tu fais pas de mise à jour sur les comptes abandonnés (puisque plus personne s'y connecte).


sinon dans la logique:
Citation :Pour un incrément automatique de 10 unité de money:
"UPDATE comptes SET money = '100' WHERE money = '90'"
"UPDATE comptes SET money = '90' WHERE money = '80'"
etc
tu peux aller direct à
"UPDATE comptes SET money = money +10"
(une requête sans condition c'est plus light que plusieurs avec; après si t'arrive pas à tout passer -mais faudrait que t'ai une sacrée bdd- j'aurais tendance à fragmenter plutot en ajoutant LIMIT x,y; mais de toute façon 4a servirait à rien de fragmenter dans le même script, si la version seule passe pas; tu devras de toute façon lancer plusieurs fois ton script à interval et changeant les x,y ).


RE: Calcul de tour qui passe maaaal - gameprog2 - 18-02-2009

Perso l'idée de wild me plaît bien ^^


RE: Calcul de tour qui passe maaaal - Feldoran - 18-02-2009

Oui l'idée de Wild est très bien et je pense qu'elle est utilisée dans bon nombre de "jeux à PA", mais ce n'est pas du tout l'optique du jeu que j'ai créé là.
J'aime bien aussi l'idée de Mycroft que je compte utiliser pour mon prochain projet, je comptais justement m'en servir comme le dit Wild avec du "UPDATE comptes SET money = money +10".

Pour mon projet actuel, avec pas mal d'interactions entre joueurs, c'est plus compliqué. Je crains d'avoir guère d'autre solution que l'étalage des traitements, mais c'est pas tip top.
Ou alors une refonte du gameplay, avec un traitement léger des actions sans interactions entre les joueurs, puis un traitement séparé pour les interactions. Mais ça demande de grosses modifs sans être certain d'une réelle amélioration. A voir...


RE: Calcul de tour qui passe maaaal - Feldoran - 19-02-2009

En y réfléchissant bien, y'a tout de même moyen d'utiliser ces deux idées pour bien améliorer mes performances. En modifiant le gameplay et beaucoup de code, certes, mais plus j'y pense, plus je me dis que ça vaut le coup. Mieux vaut ça que de multiplier par 10 le coût d'hébergement... :p