TRAITEMENT DE TRAITEMENTS LONGS.

John Dogget Messages postés 384 Date d'inscription vendredi 18 juin 2004 Statut Membre Dernière intervention 7 mai 2009 - 21 juin 2007 à 14:59
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 - 23 juin 2007 à 22:59
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/43205-traitement-de-traitements-longs

cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
23 juin 2007 à 22:59
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 !)
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
23 juin 2007 à 22:58
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é ? :(
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
22 juin 2007 à 14:56
"(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? ^ ^
"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 !
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
22 juin 2007 à 12:43
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... :)
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
21 juin 2007 à 17:08
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. :)
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/>
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
21 juin 2007 à 16:50
@ 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... :)))
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
21 juin 2007 à 16:40
...Ca me fait penser que mon application ne fonctionnera pas avec des TThreads...
Il faudra alors créer plusieurs fiches, une par Thread...
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é !
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
21 juin 2007 à 16:27
... 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.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
21 juin 2007 à 16:10
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... :)
John Dogget Messages postés 384 Date d'inscription vendredi 18 juin 2004 Statut Membre Dernière intervention 7 mai 2009
21 juin 2007 à 16:00
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 ...
John Dogget Messages postés 384 Date d'inscription vendredi 18 juin 2004 Statut Membre Dernière intervention 7 mai 2009
21 juin 2007 à 15:11
Ben oui, il manque les sources (c'est pas rien) !!

:D
cs_Loda Messages postés 814 Date d'inscription vendredi 3 novembre 2000 Statut Membre Dernière intervention 30 juillet 2009 3
21 juin 2007 à 15:01
oui, il manquait la capture d'écran. MDR !

A+

Loda

PS: je regarderais ça avec attention quand il y aura les sources ;-)
John Dogget Messages postés 384 Date d'inscription vendredi 18 juin 2004 Statut Membre Dernière intervention 7 mai 2009
21 juin 2007 à 14:59
Manquerait pas quelque chose par hasard :p ?
Rejoignez-nous