Onheartbeat ou fonction recursive ?

Répondre
Partager Rechercher
tout est dans la question mais pour être plus précis , j'ai l'intention de mettre en place la gestion de la soif et de la faim et tous les scripts que j'ai trouvé sont sur le onheartbeat du module...
N'est ce pas moins coûteux en ressource de mettre un delayCommand sur un script récursif...genre toutes les 10 à 20 minutes ?

Si quelqu'un à la moindre idée ...
D'ailleurs il me vient une autre question : quelles sont les moyens de vérifier l'optimisation du code. Existe t-il un test de performance facile à mettre en place, genre benchmark pour le nwnscript. (hormis le test en réel avec 10 joueurs ..)
Merci d'avance pour vos réponses
Pour tous les logiciels de performances, je ne sais pas.... Mais tu devrais vérifier sur le vault.


Par contre, je peux te dire que OnHeartBeat = DANGER . Car c'est le trigger bouffeur de ressource par excellence.

Donc moi pour passer outre, la plupart de mes gros systèmes se fait par une fonction récursive dans le OnModuleLoad.


Voilou
Thumbs up
Merci , c'est bien ce que je me disais. C'est étrange de trouver autant de scripts sur le vault déclenchés sur onhearbeat ...
Bon me reste plus qu'à chercher un script de bench alors ...
Si quelqu'un à une info à ce propos, je suis toujours preneur !
Citation :
Par contre, je peux te dire que OnHeartBeat = DANGER . Car c'est le trigger bouffeur de ressource par excellence.
Je me tuerais à le dire, le OnHeartBeat N'EST PAS A PROSCRIRE !!!

Si on y reflechis, c'est un script exécuté toutes les 6 secondes. En quoi cela est ce bouffeur de ressources ? Avez vous une idée de combien d'opérations de se genre sont exécuté, rien que toutes les dixièmes de secondes... Alors un de plus ou un de moins toutes les six secondes, quelle différence.....

ATTENTION : je parle la des OnHeartBeat assignés a des objets peu nombreux, comme le module par exemple. Ne pensez même pas mettre un script de ce genre sur chacuns de vos npc par exemple....
Mais passer tout les joueurs en revue par le OnHeartBeat, rien de bien méchant...

CELA DIT, pour ton exemple, j'utiliserais plutôt les évenements récursifs, comme dans la plupart des cas, je trouve ca vraiment plus propre qu'un OnHeartBeat (j'ai entre autre crée l'évenement "OnHourPassed", ou encore "OnDay" et "OnNight" dans mon module, par utilisation de fonction récursives

pour la réalisation, bien....

Code PHP:

void OnEachOurPassed()
{
    
object oPC GetFirstPC();
    while(
GetIsObjectValid(oPC)
    {
        
//Application de l'effet de faim, soif, fatigue ou autre
        //......
        //......
        //......
        
        
oPC GetNextPC();
    }
    
    
DelayCommand(3600.0fOnEachOurPassed();

Perso, j'ai un HeartBeat sur chaque creature en jeu, mais bon, faut bien le faire, avec des returns aux endroits strategiques :

Toute facon, l'event se lance quoi qu'il arrive, donc qu'il se lance pour faire une ligne avec un check-return ou rien, c'est presque pareil...

Par contre faut l'optimiser, je dis pas... ^^
@ Azraël :
Citation :
void OnEachHourPassed()
{
object oPC = GetFirstPC();
while(GetIsObjectValid(oPC))
{
//Application de l'effet de faim, soif, fatigue ou autre
//......
//......
//......

oPC = GetNextPC();
}

DelayCommand(3600.0f, OnEachHourPassed());
euh juste pour pinailler ...plus sérieusement je te remercie beaucoup pour ton aide
J'ai vu que tu avais modifier ton script d'émulation de onHeartBeat, mais je ne comprends pas l'utilité de compter le nombre de PC sur un module, un while ne suffit-il pas ?
Est-ce plus efficace ? (optimisation quand tu nous tiens...)
vi j'avais pas compiler, c'était juste un exemple rapide en passant

Citation :
j'ai entre autre crée l'évenement "OnHourPassed", ou encore "OnDay" et "OnNight"
la y'a la preuve que je savais bien que "hour" prenait un h, mon honneur est sauf ^_^

Citation :
J'ai vu que tu avais modifier ton script d'émulation de onHeartBeat, mais je ne comprends pas l'utilité de compter le nombre de PC sur un module, un while ne suffit-il pas ?
l'utilité de ce script est d'activer le onheartbeat uniquement si un joueur est dans la zone. Il faut donc le désactiver quand il n'y a plus personne, et pour cela compter le nombre de pc dans la zone(le retenir dans une var local est bien plus rapide que passer en revue tout les joueurs ou tout les objets de la zone pour en extraire les joueurs)
Citation :
Toute facon, l'event se lance quoi qu'il arrive, donc qu'il se lance pour faire une ligne avec un check-return ou rien, c'est presque pareil...
Je ne pense pas eMRaistlin, si tu ne mets pas de scripts du tout, aucun "événement" n'est lancé à mon avis, mais ce n'est que mon avis.
Sinon, tout à fait d'accord avec Azraël pour dire que si t'as besoin du OnHeartbeat, et bien c'est cela qu'il faut utiliser, si c'est pour faire exactement la même chose, en plus lent et moins robuste avec des DelayCommand, c'est pas la peine....

Par contre, bien sûr le OnHeartbeat est un slot pour lequel cela devient rentable d'optimiser le code, essayer donc de limiter les opérations effectuées à chaque battement au minimum, et pour reprendre un conseil de BubaDragon éviter d'y parcourir toutes la hiérarchie des objets. Pour les joueurs c'est un peu particulier, car a priori c'est encore assez efficace, et on doit pas pouvoir faire mieux à la main. Par contre GetNearestObjectByTag ou GetFirstObjectInShape surtout dans une boucle mieux vaut éviter.

Pour le DelayCommand, on va dire que j'insiste un peu lourdement, mais il faut absolument éviter les variables globales dans un script en contenant, toutes les variables dans la portée desquelles se trouve un DelayCommand sont copiées pour pouvoir être utilisées par le code retardé. Si ces variables ne sont en fait que des constantes, tant pis pour la lisibilité il faut les supprimer, ou alors utiliser le compilateur de Torlack.
Citation :
Par contre GetNearestObjectByTag ou GetFirstObjectInShape surtout dans une boucle mieux vaut éviter.
euh... le GetNearestObjectByTag n'est pas forcement plus lourd que le GetObjectByTag (y'a une variable en plus a vérifier, mais rien de bien gros), le problème vient du GetObjectByTag lui même, qui passe en revue touts les objets de la liste chainée des objets, ce qui est quand même asset lourd...
Enfin, c'est perssonnelement la seule méthode que je voit pour trouver un objet en fonction de son tag parmis tout les objets qu'il y a.

Pour ce qui est des constantes, j'ajouterais qu'en plus c'est pas propre ^_^
Personnelement j'en utilise pas, je fais tout passer par les arguments des fonctions quand necessaire
Citation :
euh... le GetNearestObjectByTag n'est pas forcement plus lourd que le GetObjectByTag (y'a une variable en plus a vérifier, mais rien de bien gros), le problème vient du GetObjectByTag lui même, qui passe en revue touts les objets de la liste chainée des objets, ce qui est quand même asset lourd...
Oui, GetObjectByTag aussi vaut mieux éviter
Je voulais juste dire que le script de OnHeartBeat, ce n'est qu'un script comme les autres, void main(){}, tout comme un sort, par exemple.

Or, il faut que ce script soit declenché par un evenement, et en l'occurence, cet evenement recursif scan tout les objets pour verifier s'il y a un OnHeartBeat a lancer. Au niveau temps/machine, je suis convaincu que la difference entre ce scan d'evenement potentiels qui scan des blancs, ou le meme qui scan des Void main(){return;} est relativement similaire (a quelques tours d'horloges pres, bien entendu).

Y'a une limite que tu ne peut pas abaisser, je veux dire, et le but, c'est de se rabaisser de cette limite. Mais le fait de ne pas mettre de script de OnHeartBeat, a mon avis, n'empeche pas ce "scan" Donc, pour moi, les DelayCommand, ou les OnHeartBeat OPTIMISES ne sont pas vraiement differents...


Maintenant, je suis pas un pro de l'info comme vous, donc bon, je m'avance peu etre. mais c'est comme ca que je vois la chose...
(j'ai une vision peut etre un peu trop sequentielle de la chose, c'est possible )
Tout a fait daccord, c'est ce que je me tue a expliquer sur ce forum depuis a peu près 8mois ^_^

J'utilise plutot les DelayCommand parsque c'est a mon gout plus propre, on ne s'encombre pas avec un script dans le OnHeartBeat avec plein de GetTimeHour, incrémentations de variables et compagnie, on a juste a spécifier le temp qu'il nous faut...

Mais bon, chacun sa facon de programmer, et je concoit totu a fait que certain d'entre vous préfère le OnHeartBeat, peu être plus abordable.
Je ne suis pas un pro de l'info non plus , loins de là, mais je ne pense pas que le moteur passe en revue tous les objets pour lancer les OnHeartBeat. Sous une forme ou sous une autre, une liste peut être constituée de tous les objets ayant un OnHeartbeat ; le moteur parcourrait seulement cette liste, lançant les Heartbeat les uns après les autres. Ceci est évidemment caricatural étant donné la désynchronisation et le fait que les heartbeat sont lancés plus souvent dans les zones actives que dans celles qui ne le sont pas, et il est probable que la gestion des heartbeat ne soit pas fondamentalement séparée de celle des autres types d'événements. Mais grosso modo cela illustre le fait que si tu ne mets pas de OnHeartBeat du tout sur un objet, tu ne le rencontreras pas dans la queue. Ceci dit, encore une fois un DelayCommand n'est pas forcément mieux ; et certainement pas même, au contraire, s'il fait exactement la même chose que le Onheartbeat (par exemple appel récursif depuis le spawn d'une créature jusqu'à à sa destruction).
Sans vouloir insinuer que je suis un pro de l'informatique (ce n'est pas le cas je suis lycéen ^^), ce que tu dis la me semble fort peu probable, car ridicule d'un point de vue de l'optimisation (il faut quand même chercher dans la liste définie), j'imagine plutot la solution de eM. Enfin, la encore je peux me tromper...
Personnellement je n'ai jamais dis qu'il fallait bannir le onheartbeat, j'ai dis que c'est un danger pour le fait de mettre trop de code dedans peut faire prendre de la ressource...

Donc voilà, je préfere justifier ce que je voulais dire
Citation :
(il faut quand même chercher dans la liste définie)
Non, pourquoi? dès que le moteur à fini d'exécuter un script, il prend le premier, le sort de la liste, l'éxecute, et passe au nouveau premier. Une pile FIFO quoi, peut-être que je me trompe sur le principe de base, et en tout cas il est tout à fait certain que ce qui suit est n'importe quoi:

Parser tous les objets à chaque fois me semble encore moins optimisé, maintenant je suis plutôt un matheux moi, pas un informaticien . Mais surtout les heartbeats sont asynchrones, non seulement ils ne se produisent pas tous en même temps, mais même à intervalle variable, ce qui me fait penser qu'il y a probablement une pile constituée par les événements, il est possible que quand un événement de type heartbeat sort de la pile, il y soit automatiquement réinjecté. Tu me dira il faut bien qu'il y soit mis la première fois... Mais ceci peut être fais à la création (spawn) de l'objet (d'où mon histoire de liste un peu confuse, pour un informaticien j'en suis conscient), dans ce cas pas besoin de parser quoique ce soit, tu as la référence à l'objet qui appelle le heartbeat à portée de main, et plus tard tu la reproduis au moment de la réinjection dans la pile. Je laisse volontairement de côté le problème du délais entre les heartbeat de côté, est-ce que cela marche selon le même mécanisme que le DelayCommand? Est-ce que le moment de l'exécution souhaité est associé à chaque événement qui le nécessite dans ma liste imaginaire, et que si cette condition n'est pas remplie quand l'événement pop à la surface il est réinjecté en queue de pile. Peut-être. Toujours est-il que si je spéculais sur ce terrain je dirais probablement n'importe quoi.
Encore une fois, le principe de base est probablement mauvais, et les détails sont de mon inventions , je crois que c'est à peu près ce fonctionnement qu'avait suggéré Miriandel, mais je peux aussi avoir complètement déformé ce qu'il disait. Mais tout ça c'est pour dire que je ne pense pas que parser tous les objets à chaque heartbeat soit vraiment la seule possibilité, ni même que cela corresponde très bien à ce que l'on observe. .

PS: quelqu'un veut faire l'expérience d'appeler Eyrdan à la rescousse en tapant l'adresse de son site?
Je ne suis pas sûr que même Eyrdan puisse nous aider sur ce sujet (bon il pourrait toujours nous éclairer sur l'optimisation et suggérer d'autres possibilités, d'accord), vu que le "scheduler" des systèmes temps-réel a toujours été un sujet complexe et abordable par de multiples chemins...

En bref tant que NWN ne sera pas Open Source, tout ce que nous dirons sera pure spéculation, et il est fort possible qu'aucune des solutions envisagées ici n'ait été retenue......
Tiens, à propos, les pros me corrigeront s'il faut, mais je crois qu'il faut faire la distinction normalement entre les fonctions récursives et les fonctions récurrentes. Les récursives s'appellent elles-mêmes un nombre variable de fois, comme par exemple :

Code PHP:

void Truc()
{
  
Truc();

(Bon, ok, ça c'est de la récursivité qui tue. )

On notera que dans ce genre d'appels, la fonction n'est "dépilée" qu'à la fin de son exécution complète (dans l'exemple, elle ne le sera donc jamais et bouclera jusqu'au stack overflow). Une nouvelle version de la fonction est créée en mémoire à chaque appel (avec duplication de ses variables, donc) et n'est donc détruite que lors de l'éventuel dépilage. Ca peut paraître très lourd, mais c'est un peu comme pour le onHeartBeat : si on optimise proprement, ça ne coûte pas grand chose et c'est très utile (il faut veiller à ce que la fonction ne soit pas énorme, qu'elle n'ait pas trop de variables, qu'elle soit effectivement dépilée sous certaines conditions, etc).


Les récurrentes ne sont pas empilées, ce sont des fonctions qui sont appelées toujours au même niveau, à intervalles réguliers. En général, elles sont liées à un timer ou un scheduler et prennent beaucoup moins de place en mémoire (c'est le scheduler qui gère leurs appels). Un exemple :
Code PHP:

void Truc()
{
  
DelayCommand(10.0Truc());

Après avoir interprété le DelayCommand, le script continue et termine la fonction, en créant un appel à Truc() à t+10 dans le scheduler. Le reste de la fonction s'exécute donc normalement et à la fin elle est immédiatement dépilée (libérée de la mémoire). La charge mémoire est nettement moins importante que pour la récursivité, mais ça ne sert pas du tout à la même chose. Les "émulations" de onHeartBeat par les DelayCommand sont censés être des appels récurrents (et pas récursifs), ou sinon j'ai rien compris...
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés