Calcul dans un thread et affichage progressbar : des commentaires ?
el_teedee
Messages postés497Date d'inscriptionmercredi 7 juillet 2004StatutMembreDernière intervention13 juillet 2015
-
19 juil. 2005 à 10:40
el_teedee
Messages postés497Date d'inscriptionmercredi 7 juillet 2004StatutMembreDernière intervention13 juillet 2015
-
2 août 2005 à 09:18
Bonjours à tous,
c'est sans doute une chose que tout le monde à déjà rencontré. Un
calcul qui prend du temps, et une form qui reste blanche lorsque l'on
lance ce calcul. J'ai donc parcouru le forum à la recherche d'une
solution, et j'ai vu qu'il fallait mettre le calcul dans un thread
séparé.
Alors voilà, je me demande si la méthode que j'utilise est la bonne au
niveau des performances, et au niveau de l'affichage. C'est la première
fois que j'utilise la notion de multithreading, donc je ne sais pas si
tout est correct : voilà comment je procède :
<hr size="2" width="100%">//Clique sur le bouton : créer le fichier txt :
//region Démarrer le rafraichissement de la
progressbar
timer_C_Progressbar.Start();
bt_C_Creer_txt.Text = "Annuler";
bt_C_Remplir_Cases.Enabled = true;
}
else
{
thread_ecriture.Abort();
timer_C_Progressbar.Stop();
bt_C_Creer_txt.Text = "Créer le fichier";
}
}
<hr size="2" width="100%">thread_ecriture.Start();
appelle la fonction qui prend au moins une minute, dans laquelle je met à jour une variable publique int_pourcentage_progressbar1qui me donne le pourcentage d'avancement de ma boucle.
timer_C_Progressbar.Start(); démarre un timer qui, toutes les secondes regarde la valeur de int_pourcentage_progressbar1.
<hr size="2" width="100%">//Rafraichissement de la progressbar :
//Remplissage du pourcentage pour la progressbar :
int_pourcentage_progressbar1 = 100;
//region Ecriture dans fichier txt :
try
{
using (StreamWriter sw = new
StreamWriter(Path_Repertoire + text_C_Num_Fichier.Text + ".txt"))
{
sw.WriteLine(contenu);
}
}
catch (Exception a)
{
Console.WriteLine("The file could not be written:");
Console.WriteLine(a.Message);
}
}
<hr size="2" width="100%">Le calcul se déroule bien, et le rafraichissement de la progressbar semble correct. Cependant, je me suis rendu compte que thread_ecriture.Abort(); n'arrete pas le calcul.
Je me demande aussi si cela n'irait pas plus vite d'écrire le string
contenu dans le fichier txt a chaque boucle plutôt qu'une fois à la
fin, car je me suis rendu compte que la durée d'une boucle augmente de
plus en plus que "contenu " est grand. Par exemple, une boucle dure 2ms
au départ et plus de 10ms lorsque "contenu" contient 2000 lignes. A
votre avis ?
1°) Est-ce que vous trouvez cette procédure pour la progressbar correcte ?
cs_niky
Messages postés168Date d'inscriptionjeudi 28 juin 2001StatutMembreDernière intervention18 octobre 20087 21 juil. 2005 à 15:33
On peut faire plusierus remarques quant à ton code.
Premièrement, tu définis la prioriété du thread à "Highest". Lorsqu'un thread doit s'exécuter en arrière plan, on place généralement cette valeur à "Low". Quand il s'agit d'un thread de premier plan, sa priorité est mise à "Normal".
Les valeurs "Above normal", "Hight" et "Highest" sont généralement réservés à des tâches du système d'exploitation.
Ensuite, tu fais une légère erreur en rafraichissant ta barre de progression avec un Timer. Il est plus judicieux, et moins risqué, de le faire directement dans le thread de cette façon :
float pc = (100 * i) / Convert.ToInt32(text_C_Nb_Lignes.Text);
if (int_pourcentage_progressbar1 != Convert.ToInt32(pc))
{ progressBar1.Value int_pourcentage_progressbar1 Convert.ToInt32(pc);
}
Enfin, tu fais une erreur dans l'agencement de ton code et c'est pour cela que tu ne parviens pas à arrêter le thread en cours de calcul. Ton code devrait ressembler à cela
private Thread thread_ecriture = null; // A placer à l'extérieur de toute fonction.
private void bt_C_Creer_txt_Click(object sender, System.EventArgs e)
{
// il NE faut PAS écraser l'instance de "thread_ecriture" à l'entrée de
// cette fonction.
// sinon, thread_ecriture.Abort() va arrêter un nouveau thread et pas celui
// qui existait déjà.
if (bt_C_Creer_txt.Text == "Créer le fichier")
{
//region Démarrer l'écriture
thread_ecriture.Start();
//region Démarrer le rafraichissement de la progressbar
timer_C_Progressbar.Start();
bt_C_Creer_txt.Text = "Annuler";
bt_C_Remplir_Cases.Enabled = true;
}
else
{
thread_ecriture.Abort();
timer_C_Progressbar.Stop();
bt_C_Creer_txt.Text = "Créer le fichier";
}
}
Pour terminer, il est normal que ton programme ralentisse au fur et à mesure de l'exécution du thread.
Le fait de concaténer des chaînes revient à trainer un sac de plus en plus lourd.
Pour accroître (considérablement) les performances, remplace ta chaîne par un objet StringBuilder :
System.Text.StringBuilder contenu = new System.Text.StringBuilder();
Remplace ensuite les lignes du type
contenu += "MES"
par
contenu.Append("MES")
A la fin, tu feras juste ceci :
sw.WriteLine(contenu.ToString());
el_teedee
Messages postés497Date d'inscriptionmercredi 7 juillet 2004StatutMembreDernière intervention13 juillet 20159 26 juil. 2005 à 09:46
Merci pour ces précisions constructives.
Désolé de ne pas avoir répondu plus tôt je suis reparti sur un autre problème.
Sinon, je viens de modifier la façon dont je rafraichis ma progressbar,
c'est ok. En ce qui concerne les temps d'éxécution, j'ai modifié juste
après mon premier post la façon dont je procédais, et en fait, j'écris
ligne à ligne dans mon fichier, au lieu d'attendre d'avoir un string
énorme. (sorti du contexte, on se poserait des questions lol)
Enfin, en ce qui concerne le problème avec mon thread, j'ai compris
l'erreur. Quand je cliquais sur le bouton, il me faisait une nouvelle
instance de thread_ecriture, donc il ne retourvait plus l'ancien.
Par contre, j'ai juste un petit souci au niveau suivant : quand j'abord
mon thread, il ne ferme pas bien mon objet StreamWriter, et si je veux
recliquer sur le bouton pour recommencer le thread mais dans un nouveau
thread va-t-on dire, et bien il me dit (tout naturellement, je le
concois) :
Une exception non gérée du type 'System.IO.IOException' s'est produite dans mscorlib.dll
Informations supplémentaires : Le processus ne peut pas accéder au
fichier "D:\Essais Fichiers\27.txt", car il est en cours d'utilisation
par un autre processus.
Comment je peux faire pour close mon StreamWriter après un thread.abord ?
est générée dans le thread après l'invocation à Abord.
En clair, tu peux fermer le flux de sortie comme cela :
private void Remplir_Contenu()
{
try
{
// Code principal du thread ...
}
catch (ThreadAbortException)
{
// Mettre ici le code pour terminer les opération du thread
}
// le code ici NE sera JAMAIS exécuté si le thread a été abandonné
}
Il y a juste un truc à savoir : l'exception se re-produit à nouveau
après le bloc catch. De ce fait, si le thread a été abandonné, le code
situé après catch n'est jamais exécuté (c'est ainsi fait pour que le
thread s'achève à un moment où à un autre).
Il existe une manière d'empêcher l'exception de se reproduire continuellement. Pour cela il faut écrire ceci :
try
{
// Code principal du thread ...
}
catch (ThreadAbortException)
{
// Mettre ici le code pour terminer les opération du thread
Thread.ResetAbort();
}
mais il s'agit là de faire attention à ne pas bloquer l'arrêt du thread :
el_teedee
Messages postés497Date d'inscriptionmercredi 7 juillet 2004StatutMembreDernière intervention13 juillet 20159 2 août 2005 à 09:07
ok j'ai pigé le coup du abord.
Les 2 lignes suivantes
timer_C_Progressbar.Stop();
bt_C_Creer_txt.Text = "Créer le fichier";
ne sont plus dans private void bt_C_Creer_txt_Click(object sender, System.EventArgs e)
mais on les place directement dans le code de ce que fait le thread, dans la branche qui capte l'exception générée lord du .abord()
Le coup du Thread.ResetAbort(); j'ai pigé aussi, en revanche le coup du while(true), je pense que c'est pour ne pas être bloqué dans le try catch, mais suis pas sur ;)
Vous n’avez pas trouvé la réponse que vous recherchez ?
el_teedee
Messages postés497Date d'inscriptionmercredi 7 juillet 2004StatutMembreDernière intervention13 juillet 20159 2 août 2005 à 09:18
Sinon, j'ai un chtit problème lorsque j'annule mon thread, donc la
création de mon fichier, il faut supprimer le fichier qui vient d'être
commencé et annulé.
Une exception non gérée du type 'System.Threading.ThreadStopException' s'est produite dans mscorlib.dll
Informations supplémentaires : Le thread était en cours d'arrêt.
au niveau de la ligne File.Delete(Path_Repertoire + text_C_Num_Fichier.Text + ".txt");
J'ai mis alors Thread.ResetAbort() à la dernière ligne et ca pose plus de problème. Je sais pas si c'est la meilleure méthode
Par contre, ton while(true), cela ne va pas, lorsqu'il y a un arrêt du thread par annulation, le programme retourne dans le code du thread et réexécute le thread !