begin process at 2008 07 25 21:18:06
1 216 493 membres
446 nouveaux aujourd'hui
14 182 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

TRAITEMENT DE TRAITEMENTS LONGS.


Information sur la source

Catégorie :Date & Heure Classé sous : progressbar, attente, traitement, heure Niveau : Débutant Date de création : 21/06/2007 Date de mise à jour : 22/06/2007 12:20:18 Vu / téléchargé: 3 416 / 440

Note :
Aucune note

Commentaire sur cette source (16)
Ajouter un commentaire et/ou une note


Description

(Héhéhé, j'aime bien le titre...)

Salut,
Quand votre application doit effectuer des traitements longs, il y a quelques règles de bon sens à respecter :

1) Indiquer à l'utilisateur qu'un long traitement commence. C'est le minimum pour que l'utilisateur ne "tue" pas la tâche en disant 'encore un bazar qui plante...'
2) Lui indiquer par une barre de défilement que ça continue de bosser et que c'est pas planté au milieu du gué.
3) Si possible lui indiquer le temps restant. Pratique pour pipi, café...( j'en connais même un qui en profite souvent pour se mijoter un petit chili con carne...).
4) Lui permettre d'annuler le traitement en cours si c'est pas un grand patient.

J'ai donc regroupé toutes ces règles dans une unité (Wait) que vous pourrez utiliser à votre guise.
Dans Main, il y a quelques exemples d'utilisation et de mise en oeuvre.
Dans la pratique, on ne donnera bien sûr pas les choix proposés ici à l'utilisateur; ce qui simplifiera considérablement le code d'appel.

Conclusion

Inspiré des conseils de Olivier DAHAN dans son livre "Delphi 7 Studio".
Merci à lui.
Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

21 juin 2007 14:49:01 :
J'avais oublié la capture d'écran :s
21 juin 2007 15:04:06 :
Le serveur fait des siennes ;)
22 juin 2007 12:20:18 :
Ajout d'une simulation de téléchargement.
  • signaler à un administrateur
    Commentaire de John Dogget le 21/06/2007 14:59:12

    Manquerait pas quelque chose par hasard :p ?

  • signaler à un administrateur
    Commentaire de Loda le 21/06/2007 15:01:14

    oui, il manquait la capture d'écran. MDR !

    A+

    Loda

    PS: je regarderais ça avec attention quand il y aura les sources ;-)

  • signaler à un administrateur
    Commentaire de John Dogget le 21/06/2007 15:11:53

    Ben oui, il manque les sources (c'est pas rien) !!

    :D

  • signaler à un administrateur
    Commentaire de John Dogget le 21/06/2007 16:00:59

    C'est mieux avec les sources :)

    Concernant la sources, est ce que ce n'est pas mieux d'inclure ce genre de code directement dans les traitements que dans une unité à part ?

    Je m'explique ...

    Si je prends l'exemple simple d'une copie de fichier "custom" qui n'utilise pas les API.
    Le temps indiqué et la progression peuvent dépendre de pleins de choses (charge CPU, fragmentation etc). Alors comment quelque chose d'externe à ces traitements pourrait'il etre au courant de tout ça ?

    J'ai du mal à expliquer ce que je veux dire, je vous felicite si vous m'avez compris :D ...

  • signaler à un administrateur
    Commentaire de Caribensila le 21/06/2007 16:10:55

    Salut,

    Bein, la progression est incrémentée par l'appel régulier d'une fonction de l'unité Wait, et ceci depuis la boucle provoquant l'attente. La progression reflète donc exactement ce qui est en train de se passer.

    Si j'ai bien compris ce que tu voulais dire...  :)

  • signaler à un administrateur
    Commentaire de Caribensila le 21/06/2007 16:27:58

    ... Je précise que le temps restant calculé n'est qu'une estimation. Mais cette estimation est évaluée à chaque pas du Timer. Elle pourra donc varier en fonction de la charge du CPU, par exemple.

  • signaler à un administrateur
    Commentaire de florenth le 21/06/2007 16:39:52

    Hum, ce code source me laisse dubitatif ...

    Déjà, je salue l'idée. Car par les temps qui courent, on voit de moins en moins ce genre de précautions, on ne dit même plus à l'utilisateur "je travaille", c'est à lui de le deviner. Rien que pour ça, je dis bravo.

    Après, niveau code, j'ai du mal à voir dans quels cas on pourrait utiliser un tel mécanisme ? Je veux dire, concrètement... tous les traitements longs ne sont pas des boucles. Tous les traitements longs ne s'arrêtent pas dans la seconde qui suit. Surtout lorsqu'on utilise des APIs qui travaillent sur les fichiers ou sur internet.
    Comment adapter ton code dans ces cas là ?
    Et puis, tout traitement long ne devrait-il pas être encapsulé dans un thread qui se chargerait d'indiquer par messages (pas pas synchro, on perd trop de temps) son état ?

    Pour le calcul du temps restant: pour être davantage précis, il faudrait se baser sur les dernières secondes écoulées du calcul. Car, en effet, si tu démarres la tache alors qu'il n'y a aucun programme d'ouvert, ça ira vite. Si, au milieu de la tâche, tu as une soudaine envie de lire tes mails, le programme (Thunderbird que je conseille) va la ralentir et le temps restant sera erroné !

  • signaler à un administrateur
    Commentaire de Caribensila le 21/06/2007 16:40:05

    ...Ca me fait penser que mon application ne fonctionnera pas avec des TThreads...
    Il faudra alors créer plusieurs fiches, une par Thread...

  • signaler à un administrateur
    Commentaire de Caribensila le 21/06/2007 16:50:57

    @ Florent:
    Quand tu travailles sur Internet, par exemple, il est impossible d'évaluer le temps restant. Dans ce cas, tu ne peux dire à l'utilisateur qu'une tâche est en cours et éventuellement le renseigner sur l'avancement de la tâche.
    Dans ces cas là, mon code ne donne que le temps écoulé depuis le début.
    Il ne peut pas faire l'impossible, hélas...  ;)

    "Pour le calcul du temps restant: pour être davantage précis, il faudrait se baser sur les dernières secondes écoulées du calcul."
    Je vais y réfléchir... :)))

  • signaler à un administrateur
    Commentaire de florenth le 21/06/2007 17:00:26

    Pour les threads: non, tu crées un thread par action mais tu met ta fiche dans le thread principal (et puis, t'a pas le choix en plus ^^). Pour communiquer, ce sera par messages windows ou bien par events suivant les cas...

    "Il ne peut pas faire l'impossible": cela dit, tu peux quand même estimer le temps restant sur internet à partir d'une dizaine de secondes d'action. Ce sera un temps théorique, càd si aucune perturbation n'intervient. En répétant le calcul toutes les 10 secondes, tu affines de plus en plus le temps restant mais en même temps l'utilisateur peut croire à une gruge (cf, les dernières secondes de téléchargement, il reste "2 sec2 au compteur mais qui en durent 20 ! Ou alors en cas de perturbation, tu peux rester à "dix minutes restantes" pendant une bonne minute !!).

    Mais que vaut-il mieux faire ? Ne rien dire sur le temps restant au risque de décourager l'utilisateur ou bien essayer d'estimer plus ou moins correctement la durée d'attente ? Histoire que le concerné aille prendre un bain ou alors se faire un café (ça, c'est quand tu compiles du java !!! <troll/>

  • signaler à un administrateur
    Commentaire de Caribensila le 21/06/2007 17:08:18

    De toute façon, sur Internet, les estimations sont toujours hautement fantaisistes. Et je ne vois pas comment on pourrait les affiner a priori.
    Mais ça vaut le coup d'y réfléchir. C'est intéressant.  :)

  • signaler à un administrateur
    Commentaire de Caribensila le 22/06/2007 12:43:52

    Je me trompe peut-être, mais il me semble que beaucoup d'entre vous ont des doutes sur ce code  ;)

    Donc, pour en avoir le coeur net, j'ai fait une MAJ en ajoutant une simulation de chargement de fichier sur Internet.

    Conclusion, après quelques estimations fantaisistes dans les premières secondes, l'application donne une estimation très correcte du temps restant. Et plus le temps passe, plus l'estimation s'affine.
    Après réflexion, il ne semble pas qu'on puisse faire plus précis.

    En espérant avoir dissiper quelques doutes...  :)

  • signaler à un administrateur
    Commentaire de florenth le 22/06/2007 13:25:45

    "beaucoup d'entre vous ont des doutes sur ce code"

    Tiens, j'ai l'impression de faire parti du lot ! ^^
    Le truc, c'est que je n'ai pas compris comment m'en servir dans le cas d'un VRAI téléchargement de fichier sur Internet. Ta simulation est bonne, le calcul du temps restant aussi mais il manque encore un petit quelque chose pour que je puisse comprendre.

    En fait, si, j'ai compris (pas idiot non plus le type ^^). Si on utilise un TIdHTTP il suffit de mettre Initialiser(...) et OuvrirAttente(...) dans le OnBeginWork, le MAJ(...) dans le OnWork et le FermerAttente(...) + Finaliser(...) dans le OnEndWork.

    Bon. De ce côté là c'est OK. Mais pour la fin, tu fais comment ? Il faut tester la valeur de FinDemandee dans le OnWork et demander l'annulation si demandé ? Logiquement oui (et ça marche en plus ^^).

    Cependant, si ma tâche est threadée, je fais comment ? Il faudrait que je lise la variable FinDemandee pour savoir si c'est la fin. Jusque là, c'est OK. Mais si ce n'est pas la fin, je dois synchronizer le thread avec le thread principal pour pouvoir mettre à jour la barre de progression. Conclusion: je perds du temps.

    Ce n'est pas impossible pour autant même si ce n'est pas 100% optimimsé.

    ---------------------------------------------------------------

    Maintenant, imaginons quelque chose de beaucoup plus complexe.
    J'utilise la (fameuse ?) API DeviceIOControl() pour faire plein de trucs sympas et bizarres qui prennent du temps.
    Cette fonction ne crée aucun callback et la seule façon de l'arrêter est de faire un CancelIO().
    Il est possible d'obtenir l'avancement avec GetQueuedCompletionStatus().
    Bon.
    Comment je m'y prend moi pour gérer ce cas ?

    Vu ton code, une seule solution:
    - Je lance le tâche (tout le bazar de début des API Windows...)
    - Je crée une boucle qui a pour rôle d'appeler périodiquement GetQueuedCompletionStatus()
    - A chaque renvoi d'avancement, je mets à jour la progressbar.
    - Si l'utilisateur demande d'annuler, il y aura un test dans la boucle qui se chargera d'appeler CancelIO().

    Et ça marche ! Mais c'est drôlement compliqué ! Et en plus, tout se fait dans le thread principal.
    N'y aurait-il pas un moyen plus simple de faire la même chose ?
    C'est cela que je te demande...

    PS: Je sais, je vais chercher vraiment loin, mais c'est pour voir jusqu'où tu es capable d'améliorer ta source ! ça n'enlève rien à sa qualité et à l'estime que j'ai d'elle !

  • signaler à un administrateur
    Commentaire de Caribensila le 22/06/2007 14:56:49

    "(pas idiot non plus le type ^^)"
    C'est une pensée qui ne m'a jamais effleuré !  :)
    D'autant que tu as parfaitement compris le truc de ce code. Et je te remercie de t'être penché autant sur mon travail.

    Pour ce qui est des applications threadées, j'avoue que ça dépasse encore mes limites. Je n'ai jamais eu vraiment besoin d'y avoir recours (sauf pour des connexions TCP/IP). Et comme je n'ai aucune base en info et que je suis autodidacte, j'ai besoin de me retrouver devant une situation concrète.
    Nul doute que ça viendra un jour, mais pour le moment...

    Je suppose que ce sera un problème de synchronisation des tâches. Et peut-être que dans ce cas, un traitemennt du problème spécifique à l'application sera plus optimisé. Je ne sais pas, en fait. J'y reviendrai lorsque j'aurai fait qq progrès de ce côté-là, ok?  ^ ^

  • signaler à un administrateur
    Commentaire de Delphiprog le 23/06/2007 22:58:12 administrateur CS

    Salut à tous,

    "Pour ce qui est des applications threadées, j'avoue que ça dépasse encore mes limites."
    Je crois que c'est davantage une question d'appréhension que de difficultés techniques tant la mise en oeuvre avec Delphi est simple. Il suffit d'éviter quelques pièges grossiers et l'on obtient une application qui continue de répondre même en cas de traitement long. Par ce côté, ça rassure déjà l'utilisateur final.

    Tu t'est inspiré du code d'Olivier DAHAN : je vois que monsieur a de bonnes lectures :)
    Mais ce code, et vous êtes plusieurs à l'avoir fait remarquer, est conçu pour un usage simple et rapide. Il ne saurait régler tous les cas possibles.

    Je suis assez étonné que personne n'ait mentionné l'utilisation de callbacks, encore plus simples à mettre en oeuvre pour un résultat plus facilement personnalisable. En effet, tant qu'on transmet une fonction ou une méthode dont la signature correspond à celle attendue par la fonction appelée, on peut faire varier les effets d'une progression sans avoir à concevoir de fiches spécifiques.
    Enfin, peut-être que cetet notion de fonction callback est quelque chose qui se perd...
    Après tout, pourquoi faire simple quand on peut faire compliqué ? :(

  • signaler à un administrateur
    Commentaire de Delphiprog le 23/06/2007 22:59:42 administrateur CS

    Ah oui, j'allais oublier : quand on réalise une application console, il n'y a guère moyen de faire autrement que de faire appel à ces fameuses fonctions de callback (no forms !)

Ajouter un commentaire

Pub



Appels d'offres

Serveur et client mess...
Budget : 2 000€
Animation Flash alimen...
Budget : 6 000€
Intranet client pour t...
Budget : 5 000€

CalendriCode

Juillet 2008
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Téléchargements

Logiciels à télécharger sur le même thème :

Boutique

Boutique de goodies CodeS-SourceS