IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

C# Thread et performances


Sujet :

C#

  1. #1
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 10
    Par défaut C# Thread et performances
    Bonjour,

    Je commence à développer une application utilisant plusieurs Thread. Pour le moment l'appli est assez simple il s’agit de décoder des enregistrement dans un fichier binaire, et de les stocker dans un Dataset. Pour faire un peu plus userfreindly j’ai ajouté un ProgressBar. La visiblement si l’on veux que le ProgressBar progresse il faut maître le corps du traitement non plus dans le Thread principal (ouvert par le Form) mais dans un Thread secondaire. Et c’est la que je me heurte à un problème de performance, un code pratiquement identique (a l’exception de la déclaration et de l’ouverture du Thread) me fait passer d’un temps de traitement de 7 seconde à plus de 22…

    Y aurait il donc une façon de faire particulière pour accélérer la chose ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
     
            # region Reading File
     
            private void reading(string fileName)
            { 
                storeDs.Tables["Records"].Clear();
                dataGridView.DataSource = null;
     
                ewsd = new EwsdReader();
                ewsd.open(fileName);
                startProgression();
                RecordReader rec;
                while ((rec =ewsd.readNextRecord())!= null)
                {
                    DataRow newRow = storeDs.Tables["Records"].NewRow();
                    newRow["Index"] = storeDs.Tables["Records"].Rows.Count + 1;
                    newRow["Address"] = rec.address + 1;
                    newRow["Type"] = rec.Name;
     
                    // read inner data
                    PackageReader pkg;
                    rec.read();
                    if ((pkg = rec.packages.identify(100)) != null) newRow["DateTime"] = pkg.fields[1].Value;
                    if ((pkg = rec.packages.identify(110)) != null) newRow["ConnectId"] = pkg.fields[2].Value;
     
                    // sotre data in dataset
                    storeDs.Tables["Records"].Rows.Add(newRow);
                }
                stopReading();
            }
     
            private void startReading(string fileName)
            {
                storeDs.Tables["Records"].Clear();
                dataGridView.DataSource = null;
     
                ewsd = new EwsdReader();
                ewsd.open(fileName);
                startTime = System.DateTime.Now;
                readingTread = new Thread(new ThreadStart(readDataLoop));
                readingTread.Name = "ReadingFile";
                readingTread.IsBackground = true;
                readingTread.Priority = ThreadPriority.BelowNormal;
                readingTread.Start();
                startProgression();
            }
            private void readDataLoop()
            {
                while (Thread.CurrentThread.IsAlive)
                {
                    this.Invoke(new process(storeData));
                }
            }
     
            private void storeData()
            {
                RecordReader rec=ewsd.readNextRecord();
                if (rec != null)// End of file
                {
                    // crearte new row in dataset
                    DataRow newRow = storeDs.Tables["Records"].NewRow();
                    newRow["Index"] = storeDs.Tables["Records"].Rows.Count + 1;
                    newRow["Address"] = rec.address + 1;
                    newRow["Type"] = rec.Name;
     
                    // read inner data
                    PackageReader pkg;
                    rec.read();
                    if ((pkg = rec.packages.identify(100)) != null) newRow["DateTime"] = pkg.fields[1].Value;
                    if ((pkg = rec.packages.identify(110)) != null) newRow["ConnectId"] = pkg.fields[2].Value;
     
                    // sotre data in dataset
                    storeDs.Tables["Records"].Rows.Add(newRow);
                }
                else
                {
                    readingTread.Abort();
                    stopReading();
                }
            }
            private void stopReading()
            {
                DataView dv = new DataView(storeDs.Records);
                dataGridView.DataSource = dv;
                dataGridView.Refresh();
                stopProgression();
            }
            #endregion
    Merci d'avance.

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Par défaut
    Salut,

    Je suis pas sur de bien comprendre ce que tu fais exactement, je me pose des questions sur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while (Thread.CurrentThread.IsAlive)
                {
                    this.Invoke(new process(storeData));
                }
    Qu'est ce que c'est que cette clause dans le while ?
    Ensuite tu fais un this.invoke qui va exécuter ton délégué dans ton thread principal, à quoi bon lancer un thread alors ?

  3. #3
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 10
    Par défaut
    Bonjour,

    L'Invoke permet d'utiliser une méthode Delegate (process), dont le but est de partager l'accès aux objets créés par le Thread principal dans le Thread secondaire (ce qui dans le cas on l'on utilise pas de Delegate lève une exception).

    Mon objet EWSD, ainsi que le Dataset étant créé par le Thread principale, c'est d'après ce que j'ai pu lire la façon la plus propre de partager les objets (Framework 2.0 ou sup).

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Par défaut
    Citation Envoyé par TheGriffin
    Bonjour,

    L'Invoke permet d'utiliser une méthode Delegate (process), dont le but est de partager l'accès aux objets créés par le Thread principal dans le Thread secondaire (ce qui dans le cas on l'on utilise pas de Delegate lève une exception).
    Invoke permet de faire exécuter par le thread principal une méthode. C'est nécessaire uniquement si la méthode manipule un contrôle depuis un thread qui ne possède pas ce contrôle. Sans ça effectivement tu as droit à une exception car c'est dangereux, risque de deadlock.

    Maintenant regarde ce qui se passe avec ton code : depuis ton thread principal tu crées un thread qui demande au thread principal d'exécuter la méthode storeData. Ya comme un truc qui cloche.


    Mon objet EWSD, ainsi que le Dataset étant créé par le Thread principale, c'est d'après ce que j'ai pu lire la façon la plus propre de partager les objets (Framework 2.0 ou sup).
    C'est ce qu'il faut faire depuis un thread qui accède à des contrôles qui ne lui appartiennent pas. Et encore dans ce cas il faut bien séparer les traitements des accés aux contrôles (dans des fonctions séparées) pour demander au thread principal de ne traiter QUE les accés aux contrôles, sans ça comme dans ton code tu te retrouves avec ton thread principal qui fait tout .

    Sinon tu ne réponds pas à ma question sur le while.

  5. #5
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 10
    Par défaut
    Autant pour moi,

    Je n'avais pas compris que la question portait sur le While et non sur le Invoke. La raison pour laquelle le Invoke ce trouve dans un While c'est que sans celui-ci l'Invoke n'est exécuté qu'une seul foie pour le premier Record.

    N'ayant pas fait de C depuis plus de 10 ans, et ne faisant du C# que depuis peu, ce qui vous semble évidant ne l'est pas forcement pour moi. Ainsi il me semble que la méthode storeData est belle et bien exécutée par le Thread secondaire, et j'en veux pour preuve que si l'on exécute startReading et non reading, l'ensemble du forme n'est pas figé pendant l'exécution, on peu ainsi déplacer la fenêtre (et au passage le progressBar fonctionne, ce qui n’est pas le cas avec la méthode reading).

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Par défaut
    N'ayant pas fait de C depuis plus de 10 ans, et ne faisant du C# que depuis peu, ce qui vous semble évidant ne l'est pas forcement pour moi
    Personnellement je tutoie les gens sur les forums j'espere que ça ne te dérange pas (ça ne me dérange pas d'être vouvoyé en tout cas ). A part ça pas de soucis, on est là pour apprendre, j'espere que ma première réponse n'a pas été trop "sèche", ce n'était pas mon intention.

    Concernant la méthode Control.Invoke, tu trouveras ici la doc officielle, qui explique (assez mal il faut le dire) ce que fait cette méthode. Et ici un petit article en anglais qui semble bien expliquer les problèmes de multithreading et d'accés aux controles.


    Citation Envoyé par TheGriffin
    Ainsi il me semble que la méthode storeData est belle et bien exécutée par le Thread secondaire, et j'en veux pour preuve que si l'on exécute startReading et non reading, l'ensemble du forme n'est pas figé pendant l'exécution, on peu ainsi déplacer la fenêtre (et au passage le progressBar fonctionne, ce qui n’est pas le cas avec la méthode reading).
    Je vois une raison plausible pour laquelle la méthode storeData semble être exécutée par le thread secondaire: dans la méthode readDataLoop tu demandes au thread principal de traiter une ligne en faisant un invoke puis tu le laisses souffler le temps de repasser dans la boucle, ce qui lui laisse le temps de traiter ses messages windows et de mettre à jour la progressbar, tandis que la méthode reading ne le laisse jamais souffler (pour comprendre il faut bien voir que la méthode storeData est exécutée dans le thread principal mais que la boucle est exécutée par le thread secondaire).

    Pour te convaincre et voir quel thread exécute quoi je te conseille de jeter un oeil à l'identifiant du thread courant à 3 moment différents:
    1) au début de l'exécution de ton programme, tu récupèreras l'id du thread principal
    2) au début de la méthode readDataLoop, tu récupèreras l'id du thread secondaire
    3) dans la méthode storeData, où d'aprés moi tu vas retrouver l'id du thread principal

    Cet identifiant tu l'as dans System.Threading.CurrentThread.Id.

    Essaye aussi de compter le nombre de fois que tu passes dans le while de la méthode readDataLoop par rapport au nombre de fois que tu passes dans le while de la méthode reading, ton problème de perf pourrait peut être venir de là (cela dit les appels à la méthode Invoke peuvent aussi induire une perte de perf)

  7. #7
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 10
    Par défaut
    Ok,
    Je commence à comprendre un peu mieux, effectivement la méthode store data est belle et bien exécutée dans le Thread principal. D’où une inutilité total de mon Thread secondaire vue qu’il ne fais pas grand-chose. Du coup existe-t-il une autre solution que le Invoke pour partager des ressources e entre différents Thread ?

    Et merci pour ton aide.

  8. #8
    Membre émérite
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Par défaut
    Citation Envoyé par TheGriffin
    Ok,
    Je commence à comprendre un peu mieux, effectivement la méthode store data est belle et bien exécutée dans le Thread principal. D’où une inutilité total de mon Thread secondaire vue qu’il ne fais pas grand-chose. Du coup existe-t-il une autre solution que le Invoke pour partager des ressources e entre différents Thread ?
    Il faut distinguer deux choses:
    - les variables partagées par plusieurs threads dont les accés doivent être synchronisés (c'est à dire qu'il faut empêcher que 2 threads touchent en même temps aux mêmes variables + d'autres petites subtilités)
    - les accés à des contrôles par un thread qui n'en est pas propriétaire

    Pour le premier point c'est à toi de voir quelles variables sont partagées par tes threads et gérer la synchronisation si nécessaire, j'ai l'impression qu'il n'y a que la variable storeDs à synchroniser (peut être ewsd aussi).

    Pour le second point, il faut utiliser invoke mais uniquement pour gérer l'accés aux contrôles, pas pour tout ton traitement. En gros je vois bien comme code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    private void readDataLoop()
    {
          RecordReader rec = ewsd.readNextRecord();
          while (rec != null) //le thread va s'arreter seul qd il aura fini de lire ewsd
          {
              //Tout ton traitement sur la variable rec ici, effectué par le thread secondaire
     
              rec = ewsd.readNextRecord(); //on lit l'enregistrement suivant (toujours dans le thread secondaire)
              this.Invoke(MethodeQuiUpdateLaProgressbar); //update de la progressbar fait par le thread principal
          }
    }
    Citation Envoyé par TheGriffin
    Et merci pour ton aide.
    De rien

    PS: un excellent article sur le multithreading en .net ici.

  9. #9
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 10
    Par défaut
    Partager le traitement entre les 2 Tread est effectivement ce que j’ai commencer à faire (pour partager la valeur de EWSD, je la passe en paramètre de l’Invoke). Mais malheureusement les performances ne sont guère meilleures.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
     
            # region Slow reader (using Thread)
            private void startReading(string fileName)
            {
                storeDs.Tables["Records"].Clear();
                dataGridView.DataSource = null;
                ewsd = new EwsdReader();
                ewsd.open(fileName); 
     
                startTime = System.DateTime.Now;
                readingTread = new Thread(new ThreadStart(readDataLoop));
                readingTread.Name = "ReadingFile";
                readingTread.IsBackground = true;
                readingTread.Priority = ThreadPriority.BelowNormal;
                readingTread.Start();
                startProgression();
            }
            private void readDataLoop()
            {
                RecordReader rec;
                while ((rec=ewsd.readNextRecord())!=null)
                {
                    rec.read();
                    this.Invoke(new recordWriter(storeData),rec);
                }
                this.Invoke(new process(stopReading));
                readingTread.Abort();
            }
     
            private void storeData(RecordReader rec)
            {
                // crearte new row in dataset
                DataRow newRow = storeDs.Tables["Records"].NewRow();
                newRow["Index"] = storeDs.Tables["Records"].Rows.Count + 1;
                newRow["Address"] = rec.address + 1;
                newRow["Type"] = rec.Name;
     
                // read inner data
                PackageReader pkg;
                if ((pkg = rec.packages.identify(100)) != null) newRow["DateTime"] = pkg.fields[1].Value;
                if ((pkg = rec.packages.identify(110)) != null) newRow["ConnectId"] = pkg.fields[2].Value;
     
                // sotre data in dataset
                storeDs.Tables["Records"].Rows.Add(newRow);
            }
            private void stopReading()
            {
                DataView dv = new DataView(storeDs.Records);
                dataGridView.DataSource = dv;
                dataGridView.Refresh();
                stopProgression();
            }
            #endregion
    Hors je n'est pas l'impression que ce soit l'Invoke par lui même qui soit couteux, par exemple l'appelle de l'invoke du progressBar ne fait pas chuter les performances de façon drastique.

    A demain pour la suite...

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Par défaut
    Plusieurs choses que je ne comprends pas:

    1) que font le startProgression(); et stopProgression(); ?

    2) tu fais des invoke avec des methodes qui n'ont pas l'air de toucher à un quelconque contrôle (storeData et stopReading) et qui font donc effectuer des traitements au thread principal. Du coup la seule chose que fait ton thread secondaire en plus par rapport à la première version de ton code c'est le readNextRecord et le rec.read();

    3) pourquoi cette instruction readingTread.Abort(); sachant qu'arrivé là, la méthode se termine et le thread par la même occasion ?

    Hors je n'est pas l'impression que ce soit l'Invoke par lui même qui soit couteux, par exemple l'appelle de l'invoke du progressBar ne fait pas chuter les performances de façon drastique.
    L'invoke lui même ne fait pas chuter les perfs, ça vient d'ailleurs. Par contre jene vois pas "l'invoke de la progressBar" dont tu parles ?

  11. #11
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 10
    Par défaut
    1) Start et stopProgression sont en fait utilisé pour démarrer un 3eme Thread qui gère le progressBar. Je suis bien d’accord qu’il n’on pas vraiment d’intérêt, mais la gestion du progressBar a été ma première approche des Thread.

    2) Le DataSet storeDs est un contrôle qui à belle et bien été initialisé par le Tread principal, et tout le but du programme est de récupérer le contenu de ce dataSet pour l’afficher dans un datagridView qui fait lui aussi parti du Form. Quand à readNextRecord et rec.read (qui devrai plutôt s’appeler rec.decode) ces 2 méthodes contiennent toute l’intelligence de décodage du fichier.

    3) Ca c’est un copier coller qui traîne le abort est en effet tout a fait inutile.

    4) L’Invoke de la progressBar ce trouve dans startProgression.

  12. #12
    Membre émérite
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Par défaut
    Citation Envoyé par TheGriffin
    1) Start et stopProgression sont en fait utilisé pour démarrer un 3eme Thread qui gère le progressBar. Je suis bien d’accord qu’il n’on pas vraiment d’intérêt, mais la gestion du progressBar a été ma première approche des Thread.
    Mais si StartProgression lance un thread pour gérer la progressBar c'est ici qu'il doit y avoir des invoke, du coup je comprends plus rien.


    2) Le DataSet storeDs est un contrôle qui à belle et bien été initialisé par le Tread principal, et tout le but du programme est de récupérer le contenu de ce dataSet pour l’afficher dans un datagridView qui fait lui aussi parti du Form. Quand à readNextRecord et rec.read (qui devrai plutôt s’appeler rec.decode) ces 2 méthodes contiennent toute l’intelligence de décodage du fichier.
    Un DataSet n'est pas un contrôle, le datagridView oui. Donc pas de raison de faire un invoke d'une méthode qui touche au DataSet.


    Pourrais-tu fournir l'ensemble de ton code, épuré de ce qui concerne la lecture du fichier et autres détails, mais avec l'ensemble de ce qui concerne les threads et la progressbar, histoire d'essayer de reproduire ce que tu fais ?

    Sinon voici un petit bout de code qui montre comment j'aurais géré une progressbar : c'est une winform sur laquelle il n'y a que deux controles, un bouton btnWork et une progressbar pgProgress. Je simule une activité dans mon thread secondaire avec un Sleep et pas de 3ieme thread pour gérer la progressbar:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
     
    public partial class Form1 : Form
    	{
    		private delegate void MyDelegate();
     
    		public Form1()
    		{
    			InitializeComponent();
    		}
     
    		private void btnWork_Click(object sender, EventArgs e)
    		{
    			pgProgress.Value = 0;
    			btnWork.Enabled = false;
     
    			ThreadStart TS = new ThreadStart(Work);
    			Thread T = new Thread(TS);
    			T.IsBackground = true;
    			T.Start();
    		}
     
    		private void Work()
    		{
    			for (int i = 0; i < 10; ++i)
    			{
    				Thread.Sleep(1000); //simulation d'un boulot qui prendrait 1 seconde
    				//C'est ici qu'il faut faire tout ce qui est potentiellement long
     
    				UpdateProgress();
    			}
     
    			EnableButton();
    		}
     
    		private void EnableButton()
    		{
    			if (InvokeRequired) //si on n'est pas dans le thread principal
    			{
    				Invoke(new MyDelegate(EnableButton)); //on s'appelle soi même depuis le thread principal
    			}
    			else
    			{
    				btnWork.Enabled = true;
    			}
    		}
     
    		private void UpdateProgress()
    		{
    			if (InvokeRequired) //si on n'est pas dans le thread principal
    			{
    				Invoke(new MyDelegate(UpdateProgress)); //on s'appelle soi même depuis le thread principal
    			}
    			else
    			{
    				pgProgress.PerformStep();
    			}
    		}
    	}

  13. #13
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 10
    Par défaut
    Sphax,

    Suite à tes indications, j'ai repris mon code et tracé pas à pas chaque action. J'ai fini par identifier que la perte de performance était du au rafraîchissement du DataGridView. En fait l'affectation du control source de celui-ci était mal placé, et était effectué à chaque ajout d'enregistrements. En déplacent celui-ci à la fin du traitement on obtient même des performances légèrement supérieur à une version monoThread.

    Pour ceux que cela intéresse voici le code retouché :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
     
    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Configuration;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
     
    namespace AmaEditor
    {
        public partial class FileEditor : Form
        {
            public EwsdReader ewsd;
            private Thread progressThread;
            private Thread readingTread;
            private delegate void process();
            private delegate void recordWriter (RecordReader rec);
            private DateTime startTime;
     
            #region Form controls
            public FileEditor()
            {
                InitializeComponent();
            }
            private void dataGridView_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
            {
                DataRow currentRow = storeDs.Tables["Records"].NewRow();
                currentRow = storeDs.Tables["Records"].Rows[e.RowIndex];
                RecordReader selRec = new RecordReader(ewsd.ewsdStruct, ewsd.buffer, Convert.ToInt32(currentRow["Address"].ToString()) - 1);
                RecordEditor recEdit = new RecordEditor(selRec, string.Format("{2}{0:D6} / address {1}", e.RowIndex + 1, selRec.address + 1, selRec.Name));
                recEdit.Show();
            }
            #endregion 
     
            #region Main Menu
            public void openFile(string fileName)
            {
                try
                {
                    reader(fileName);
                }
                catch (InvalidPackageException caught)
                {
                    MessageBox.Show(caught.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                catch (InvalidRecordException caught)
                {
                    MessageBox.Show(caught.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                catch (InvalidStructureFile caught)
                {
                    MessageBox.Show(caught.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    setStructureFile();
                }
            }
            private void openFile(object sender, EventArgs e)
            {
                OpenFileDialog file = new OpenFileDialog();
                file.Filter = "AMA files (*.ama)|*.ama|ICAMA (*.icama)|*.icama|INAMA (*.inama)|*.inama|All files (*.*)|*.*";
                if (file.ShowDialog() == DialogResult.OK)
                {
                    openFile(file.FileName);
                }
            }
     
            private void setStructureFile()
            {
                OpenFileDialog file = new OpenFileDialog();
                file.Filter = "AMA structure definition (*.asd)|*.asd";
                if (file.ShowDialog() == DialogResult.OK)
                {
                    Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
                    ConfigurationManager.AppSettings["EwsdStructure"] = file.FileName;
                    config.AppSettings.Settings.Remove("EwsdStructure");
                    config.AppSettings.Settings.Add("EwsdStructure", file.FileName);
                    config.Save();
                }
            }
     
            private void editStructure(object sender, EventArgs e)
            {
                StructureEditor structEdit = new StructureEditor();
                structEdit.openFile(ConfigurationManager.AppSettings["EwsdStructure"]);
                structEdit.Show();
            }
            #endregion 
     
     
            #region ProgressBar
            private void startProgression()
            {
                startTime = System.DateTime.Now;
                message.Text = "Loading...  Please Wait.";
                //message.Refresh();
                progressBar.Minimum=0;
                progressBar.Maximum=ewsd.buffer.Length;
                progressBar.Visible = true;
                //dataGridView.Refresh();
                dataGridView.DataSource = null;
                this.Refresh();
     
                progressThread=new Thread(new ThreadStart(progressLoop));
                progressThread.Name = "Progression";
                progressThread.IsBackground = true;
                progressThread.Priority = ThreadPriority.Normal;
                progressThread.Start();
            }
     
            private void progressLoop()
            {
                while(Thread.CurrentThread.IsAlive)
                {
                    this.Invoke(new process(displayProgress));
                    Thread.Sleep(500);
                }
            }
     
            private void stopProgression()
            {
                progressThread.Abort();
                progressBar.Visible=false;
     
                DataView dv = new DataView(storeDs.Records);
                dataGridView.DataSource = dv;
                dataGridView.Refresh();
     
                DateTime stopTime = System.DateTime.Now;
                TimeSpan spent = stopTime - startTime;
                message.Text = string.Format("{0} records loaded {1:t} seconds  -> {2:} records/seconds", storeDs.Tables["Records"].Rows.Count, spent, (int)(storeDs.Tables["Records"].Rows.Count / spent.TotalSeconds));
            }
     
            private void displayProgress()
            {
                progressBar.Value=ewsd.progression;
                progressBar.Refresh();
                this.Refresh();
            }
            #endregion 
     
            #region reader (using Thread)
            private void reader(string fileName)
            {
                storeDs.Tables["Records"].Clear();
                ewsd = new EwsdReader();
                ewsd.open(fileName); 
     
                startTime = System.DateTime.Now;
                readingTread = new Thread(new ThreadStart(readDataLoop));
                readingTread.Name = "ReadingFile";
                readingTread.IsBackground = true;
                readingTread.Priority = ThreadPriority.BelowNormal;
                readingTread.Start();
                startProgression();
            }
            private void readDataLoop()
            {
                this.Invoke(new process(startProgression));
                RecordReader rec;
                while ((rec=ewsd.readNextRecord())!=null)
                {
                    rec.read();
                    // crearte new row in dataset
                    DataRow newRow = storeDs.Tables["Records"].NewRow();
                    newRow["Index"] = storeDs.Tables["Records"].Rows.Count + 1;
                    newRow["Address"] = rec.address + 1;
                    newRow["Type"] = rec.Name;
     
                    // read inner data
                    PackageReader pkg;
                    if ((pkg = rec.packages.identify(100)) != null) newRow["DateTime"] = pkg.fields[1].Value;
                    if ((pkg = rec.packages.identify(110)) != null) newRow["ConnectId"] = pkg.fields[2].Value;
     
                    // sotre data in dataset
                    storeDs.Tables["Records"].Rows.Add(newRow);
                }
                this.Invoke(new process(stopProgression));
            }
            #endregion 
        }
    }
    Encore merci pour ton aide, et à une prochaine.

  14. #14
    Membre expérimenté Avatar de scifire
    Inscrit en
    Juillet 2004
    Messages
    226
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 226
    Par défaut
    Salut
    Je ne sais pas pourquoi ne pas utiliser le composant specialement concu pour ce type de taches - BackgroundWorker Class

  15. #15
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 10
    Par défaut
    Bonjour,

    Tout simplement parceque je débute en C#, et que je ne connais pas cette class

    Donc je vais regarder cela avec le plus grand interet, merci.

  16. #16
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Sphax
    Invoke permet de faire exécuter par le thread principal une méthode.
    Non , pas exactement :ça la fait exécuter par le thread qui a instancié le contrôle, il me semble.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Thread et performances
    Par seeme dans le forum Android
    Réponses: 0
    Dernier message: 03/05/2010, 02h24
  2. thread et performance
    Par gene69 dans le forum Débuter avec Java
    Réponses: 6
    Dernier message: 13/06/2008, 18h42
  3. [Linux] Threads, performance
    Par chris_boulot dans le forum Ruby
    Réponses: 8
    Dernier message: 05/04/2008, 18h01
  4. Réponses: 5
    Dernier message: 09/10/2006, 16h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo