none
Thread/BackgroundWorker trés lent RRS feed

  • Question

  • Je viens de mettre en place un BackgroundWorkerpour gérer une partie de mon code (en vb.net) qui est très longue.
    La fonction que j'utilisais avant a été transposée dans une fonction déclenchée par l'event BackgroundWorker.DoWork
    J'ai aussi mis en place un BackgroundWorker.ProgressChanged pour suivre la progression de la tache, ainsi que BackgroundWorker.RunWorkerCompleted pour gérer la fin.

    Or j'ai remarqué que la même tache exécutée dans mon BackgroundWorker est sensiblement plus longue (X10) par rapport à la même tache dans mon thread principal.

    Puis j'ai testé avec un thread secondaire et la même constat !

    J'ai fais 3 tests :
    1) avec un backgroundworker qui exécute la même fonction + une progress barre et un label qui indique le %tage d'avancement
    2) avec un vrai autre thread qui exécute la même fonction + une progress barre et un label qui indique le %tage d'avancement
    3) dans le thread principal, comme actuellement (par exemple quand on appuie sur un bouton)

    Attention dans le cas d'un thread en plus, le thread principal continue à exécuter des fonction/requêtes mysql en même temps

    J'ai pris un rep contenant 4112 fichiers répartis dans plus de 100 rep pour un total de plusieurs Go afin de tester la rapidité des différentes solutions.

    Thread principal
    simple 2'36''
    sans report bdd 17''
    sans report bdd, ni test dispo 5''

    BackgroundWorker
    simple 5'
    sans report progress 5'09''
    sans report bdd 3'08''

    Thread secondaire
    simple  4'49''
    sans report bdd 1'35''
    sans report bdd, ni test dispo  5''

    Mon code ressemble à ça (cas du thread secondaire, pour le reste il suffit de lancer la fonction directement à partir du BGW ou du thread principal, en changeantce qui est propre à chacun) :

        Private Sub LaunchListMediaThread()
            NewMediaToList = False
            Dim Medias As String = ""
            Dim count As Integer = 0
    
            RemplListMediasThread(FilePath, Medias, count)
            If Medias.Length > 0 Then Medias = Medias.Remove(0, 1)
            MediaTab_Temp = Medias.Split("|")
        End Sub
    
    
        Sub RemplListMediasThread(ByVal RepPere As String, ByRef MediaConcatString As String, ByRef count_avancement As Integer)
            Application.DoEvents()
    
            Dim ListOfRep() As String = Directory.GetDirectories(RepPere)
    
            For indexrep = 0 To ListOfRep.Length - 1
                RemplListMediasThread(ListOfRep(indexrep), MediaConcatString, count_avancement)
            Next
    
            Dim ListOfFiles() As String = System.IO.Directory.GetFileSystemEntries(RepPere, "*.*")
    
            For indexfile = 0 To ListOfFiles.Length - 1
                count_avancement += 1
    
                SetLabelText_ThreadSafe(Me.LabelMedia, count_avancement)
                SetPBValue_ThreadSafe(Me.MediaProgressBar, count_avancement)
               
                Try
                    Dim DateCreation As Date = FileDateTime(ListOfFiles(indexfile))
                    Dim DiffDate As Integer = DateDiff(DateInterval.Minute, DateCreation, Now)
                    
                    If FileOk(ListOfFiles(indexfile),DiffDate) Then
                        MediaConcatString = MediaConcatString & "|" & ListOfFiles(indexfile)
                       AddToMediaTableBackThread(Path.GetFileName(ListOfFiles(indexfile)), "1", DateCreation.ToString("yyyy-MM-dd H:mm:ss"))
                       End If
                Catch ex As Exception
                    
                End Try
    
                Application.DoEvents()
            Next
        End Sub
    
    
        Sub AddToMediaTableBackThread(ByVal MediaFileName As String, ByVal Statut As String, ByVal DateModif As String)
            Dim MySqlString As String = "INSERT INTO " & MysqlPrefixTable & "medias (`media` ,`statut`, `filedate`) VALUES " & " ('" & MediaFileName & _
                                       "', '" & Statut & "', '" & DateModif & "')" & " ON DUPLICATE KEY UPDATE statut='" & Statut & "', filedate='" & DateModif & "';"
            Dim MyCommand As New MySqlCommand
            Dim MediaMysqlConn As New MySqlConnection
            MediaMysqlConn.ConnectionString = MyConnectionString
            MyCommand.Connection = MediaMysqlConn
            MyCommand.CommandText = MySqlString
    
            Try
                MediaMysqlConn.Open()
                MyCommand.ExecuteNonQuery()
                MediaMysqlConn.Close()
            Catch myerror As MySqlException
    
            End Try
    
            MyCommand.Dispose()
        End Sub
    
    
    
        Delegate Sub SetPBValue_Delegate(ByVal [PB] As ProgressBar, ByVal [value] As Integer)
    
        Private Sub SetPBValue_ThreadSafe(ByVal [PB] As ProgressBar, ByVal [value] As Integer)
            Dim pourcent As Integer = 0
            pourcent = CInt([value] * 100 / (TotalPrecendent + 2))
            If pourcent > 100 Then
                pourcent = 100
            ElseIf pourcent < 0 Then
                pourcent = 0
            End If
    
            If [PB].InvokeRequired Then
                Dim MyDelegate As New SetPBValue_Delegate(AddressOf SetPBValue_ThreadSafe)
                Me.Invoke(MyDelegate, New Object() {[PB], [value]})
            Else
                [PB].Value = pourcent
            End If
        End Sub

    J'ai simplifié plusieurs choses, comme FileOk qui teste si le fichier n'est pas utilisé ailleurs (en faisant une tentative de renommage) ou si sa copie est bien terminée...
    Pour les tests, j'ai retiré la gestion des exceptions pour simplifier.

    La conclusion est quand même que pour l’exécution du MÊME code dans un thread en plus,  avec les mêmes paramètres, cela prends:
    - 5 minutes avec le Backgroundworker
    - 4'49'' avec le thread de Threading.Thread
    alors que dans le thread principal cela prend 2'36.

    D’où ma question sur la rapidité des thread secondaires ET/OU si le fait de faire en même temps des requêtes dans un thread en parallèle peut ralentir un autre thread...

    Précision  l'utilisation de :

    Dim DateCreation As Date = FileDateTime(ListOfFiles(indexfile))

    sur des fichiers sur un disque réseau est très gourmande déjà, mais je n'explique pas la différence thread principal/thread secondaire...

    • Déplacé Mike Feng mardi 27 novembre 2012 10:07 (Origine :.NET Base Class Library)
    lundi 26 novembre 2012 15:25

Réponses

  • Et donc sans indiquer l'avancement cela donne quoi ? Comme je l'avais indiqué plus haut la différence que je vois sur ce code est que en avant plan on mets à jour directement l'UI tandis qu'en arrière plan on va faire 26600 "invoke" en plus pour passer d'une thread à l'autre (2 à chaque boucle) et j'avais déjà suggéré de faire le même test en mettant en commentaire les lignes :

     SetLabelText_ThreadSafe(Me.LabelUI, CInt(count_avancement * 100 / (Max(13300, count_avancement) + 2)) & "%")
     SetPBValue_ThreadSafe2
    (Me.UIProgressBar, count_avancement * 100 / (13300 + 2))

    Indiquez également SVP les mesures concrètes que l'on puisse se faire une idée de la différence. Si la différence disparait c'est bien que l'on appellle trop souvent la thread UI depuis le thread d'arrière plan comme je l'avais suggéré dans ma première réponse.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    • Marqué comme réponse Morphée jeudi 6 décembre 2012 11:06
    mercredi 5 décembre 2012 16:03
    Modérateur

Toutes les réponses

  • ReBonjour

    On ne peut faire grand-chose pour améliorer la vitesse d’un Thread ou BackgroundWorker sauf d'optimiser le code exécuté.

    On peut utilizer ProcessPriorityClass

    System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass. High;

    Plus de détails vous avez ici:

    http://msdn.microsoft.com/fr-fr/library/system.diagnostics.processpriorityclass.aspx

    mais

    Soyez extrêmement prudent lorsque vous spécifiez High comme classe de priorité du processus, car une application de classe de priorité haute peut utiliser presque tout le temps processeur disponible.


    Aurel BERA, Microsoft
    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.

    mercredi 28 novembre 2012 09:25
  • Bonjour,

    Avez-vous essayé d'activer l'optimisation de code dans les propriété de projet ?

     

    Cordialement


    Merci de valider par "Proposer comme réponse" si celle-ci répond à votre demande !

    mercredi 28 novembre 2012 10:58
  • Effectivement c'est une piste, mais dans ce cas deux questions se posent :

    - est ce que de base le thread principal, lié à mon UI de démarrage est par défaut plus rapide qu'un autre thread créé en plus?

    - est-ce que cela vaut le coup de passer en high avec les risques que cela comporte ?

    mercredi 28 novembre 2012 11:30
  • Ou se trouve cette option?

    Merci.

    mercredi 28 novembre 2012 11:31
  • Bonjour,

    1) Sans être un expert sur le sujet, à priori pas à ce point, un facteur 10x me parait énorme ! Je dirais plutôt que le traitement d'arrière plan signale trop souvent le progrès ce qui génère énormement de transitions vers le thread UI (qui si j'ai bien compris est lui-même occupé ???) ce qui est couteux (et même peut-être deux à chaque fois car on semble faire une transition pour chaque contrôle plutôt que de faire toutes les mises à jour de l'UI d'un coup). Les exceptions sont également couteuses. Au moins en mise au point, éviter de les ignorer purement et simplement. Finalement deux traitements qui utilisent les mêmes ressources (réseau, disque) vont sans doute finir par se marcher sur les pieds tout de même... Egalement voir http://msdn.microsoft.com/fr-fr/library/416y61e6.aspx et la section remarques. Je vois ConcatMediaString. Si cela génère une chaine de caractères c'est également très long (utiliser plutôt un StringBuilder ou est-ce qq chose qui n'est plus d'actualité ?).

    2) je dirais non. Cela ne va sans doute pas être le jour et la nuit et c'est plutôt le signe que qq chose ne va pas à la base. Déjà j'essaierai de voir combien de temps prends la production de la liste par rapport à son traitement.

    Que fait on en avant plan par rapport à l'arrière plan ? La première utilisation serait de libérer l'interface utilisateur. Finalement c'est un dual core ?

    Je commencerais par exemple par tester un bête calcul sans progrès pour voir quel est la différence minimale entre un traitement en avant/arrière plan...

    Après test, cela me donne par exemple au pire 1.10 vs 1.23 s sur une première exécution (on est loin d'un facteur 10 comme j'ai cru le comprendre) et généralement pas de différence significative.

    Déjà si le thread d'arrière plan appelle un thread UI qui est lui-même occupé je pense que cela pourrait expliquer en partie le problème (là aussi un petit test avec un calcul pourrait montrer ce même problème).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".




    mercredi 28 novembre 2012 18:17
    Modérateur
  • Patrice merci pour ce message très intéressant. En effet X10 est peut être exagéré et ne se produit que dans les extremes. à priori on est plutôt sur un ordre de grandeur de X2 à X8 (ce qui est déjà énorme !)

    J'ai eu un peu la même réflexion sur la possible compétition entre le thread principal et le thread secondaire. Après plusieurs tests, il semble que le thread secondaire n'est pas plus long à s’exécuter, dans les mêmes conditions, si le thread primaire est fait quelque chose ou pas. Et cela même quand le thread principal exécute lui aussi des requetes en bdd.
    Donc : le fait qu'il y en ait 2 en parallèle n'a, à priori, pas d'influence.

    Idem en ce qui concerne la mise à jour de l'UI : j'ai commenté les lignes qui faisaient avancer la progressbarre et mettaient à jour le label et aucun gain notable de temps dans le traitement.

    Au niveau de la concaténation, je me suis aussi rendu compte de la lourdeur de ce procédé et je vais essayer de faire un nouvel algorithme avec un list of() et des add(élément).

    Avec File.GetCreationTime à la place de FileDateTime (solution suggérée par Aurel Bera) j'ai gagné un peu en performance lorsque j’exécute le listage avec le thread principal, il faut que je refasse des tests avec ce changement dans le thread secondaire.


    mercredi 28 novembre 2012 18:40
  • Aurel,

    Après des tests je me suis rendu compte que System.Diagnostics.Process.GetCurrentProcess().PriorityClass va en fait changer la priorité de tout le process, et donc de tous les threads.

    Par contre, cela peut être intéressant de changer ce paramètre pour gagner un peu en perf sur la totalité de mon application, avec par exemple : AboveNormal

    jeudi 29 novembre 2012 11:25
  • ReBonjour

    J’ai testee aussi, System.Diagnostics.Process.GetCurrentProcess().PriorityClass s’applique pour toute l’application. 

    Est-il possible d’essayer de trouver une autre solution pour vérifier si le fichier est utilisé oui en cours de copie ?

    Au moins sur le réseau c’est sûr que c’est une opération couteuse comme temps.

     Je vous propose ca :

    static bool FileInUse(string path)

        {

            try

            {

                using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))

                {

                    fs.CanWrite

                }

                return false;

            }

            catch (IOException ex)

            {

                return true;

            }

        }

     Cordialement,


    Aurel BERA, Microsoft
    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.

    jeudi 29 novembre 2012 15:56
  • J'ai fait un petit test sur ma clé USB avec juste un GetFileSystemEntries sur toute l'arbo et je trouve le même temps en avant et arrière plan.

    Je ferais qq chose comme :
    - un traitement avec éventuellement en paramètre le BackgroundWorker ou Nothing (pour éventuellement indiquer la progression si présent).

    Le bouton1 lance ce traitement avec nothing, le bouton2 lance le RunWorkerAsync qui lance ce traitement avec le backgroundworker en paramètre.

    Et donc je réincorporerais toutes les étapes en testant à chaque fois jusqu'à trouver une différence significative. Chez moi je vois juste un temps plus long à la première exécution (visiblement mise en cache de la table des fichiers) mais sinon je trouve le même temps en avant et en arrière plan. Pour moi ce n'est pas inhérent à une exécution en arrière plan mais il y a qq chose de particulier dans le code qui déclenche cette différence très significative de performance entre une exécution en avant et en arrière plan (ou la mesure elle-même n'est pas bonne ?)


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    jeudi 29 novembre 2012 17:51
    Modérateur
  • Aurel : est-ce que tu ferais cela sur chacun des 13000 fichiers à chaque scan?

    Il me semblait plus approprié de d'abord regarder si le fichier était la depuis longtemps (cad copie finie depuis longtemps), avant de tester l'accessibilité, du coup mon algo ressemble à :

    Pour chaque fichier trouvé dans le répertoire et les sous-répertoires :

    Si le fichier est arrivé il y a plus de 2 minutes (créé ou modifié)
                        S'il est déja dans la précédente liste  :
                            On le garde dans la liste
                        Sinon, s'il est la depuis plus de 2h :
                            On le garde dans la liste
                            ET on l'ajoute en bdd
                        Dans tous les autres cas :
                            S'il est bien totalement arrivé = pas en cours de copie ou d'utilisation (test renommage) :
                            On l'ajoute dans la liste
                            ET on l'ajoute en bdd
                    Sinon
                       S'il est bien totalement arrivé = pas en cours de copie ou d'utilisation (test renommage) :
                            On l'ajoute dans la liste
                            ET on l'ajoute en bdd
                        Sinon
                            On refera un scan à la prochaine boucle pour voir si c'est ok

    Mais peut-être qu'il vaut mieux directement tester si le fichier est utilisé ou pas....

    jeudi 29 novembre 2012 18:07
  • Patrice, voici un code que j'utilise pour mes tests :

     Sub testsub()
            Dim test As String = ""
            Dim count_avancement As Integer = 0
            For indexfile = 0 To 13300
                Application.DoEvents()
                Try
                    Dim DateCreation As Date = FileDateTime("C:\Users\NAME\Desktop\test.txt")
                    Dim DiffDate As Integer = DateDiff(DateInterval.Minute, DateCreation, Now)
                    count_avancement += 1
                    test = test & "C:\Users\NAME\Desktop\Nom_du_fichier.ext" & ";"
                    AddToBdd("C:\Users\NAME\Desktop\Nom_du_fichier.ext", "1", DateCreation.ToString("yyyy-MM-dd H:mm:ss"))
                    SetLabelText_ThreadSafe(Me.LabelUI, CInt(count_avancement * 100 / (Max(13300, count_avancement) + 2)) & "%")
                    SetPBValue_ThreadSafe2(Me.UIProgressBar, count_avancement * 100 / (13300 + 2))
                Catch ex As Exception
    
                End Try
    
            Next
            SetLabelText_ThreadSafe(Me.LabelUI, "100%")
    End Sub
    
    ' The delegate
    Delegate Sub SetPBValue_Delegate2(ByVal [PB] As ProgressBar, ByVal [value] As Integer)
    ' The delegates subroutine.
    Private Sub SetPBValue_ThreadSafe2(ByVal [PB] As ProgressBar, ByVal [value] As Integer)
            Dim pourcent As Integer = [value]
            If pourcent > 100 Then
                pourcent = 100
            ElseIf pourcent < 0 Then
                pourcent = 0
            End If
    
            ' InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread.
            ' If these threads are different, it returns true.
            If [PB].InvokeRequired Then
                Dim MyDelegate As New SetPBValue_Delegate2(AddressOf SetPBValue_ThreadSafe2)
                Me.Invoke(MyDelegate, New Object() {[PB], pourcent})
            Else
                [PB].Value = pourcent
            End If
    End Sub
    
    'Bouton de test avec thread secondaire
    Private Sub TestButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TestButton.Click
            SetLabelText_ThreadSafe(Me.LabelUI, "0%")
            testThread.Abort()
            testThread = New Threading.Thread(AddressOf testsub)
            UIProgressBar.Value = 0
            UIProgressBar.Visible = True
            LabelUI.Text = "Refreshing list"
            testThread.Start()
            testThread.IsBackground = True
     End Sub
    
    'Bouton de test avec thread principal
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            testsub()
    End Sub

    Avec le thread secondaire j'ai fait 3 mesures : 44'', 40'', 45''
    Avec le thread principal j'ai fait 3 mesures : 32'', 34'', 36''

    jeudi 29 novembre 2012 18:41
  • Le test de renommage n'est fait que très peu souvent (au tout premier listage, et à chaque nouveau fichier arrivé), le gain en performance ne viendra pas de la...
    jeudi 29 novembre 2012 18:53
  • Que donne le même test avec mise à jour de l'avancement en commentaire et/ou AddToBdd qui ferait par exemple un return immédiat ?

    Pour l'avancement, il y a un changement de contexte en plus pour l'exécution en arrière plan et il est fait à CHAQUE boucle donc je m'attends à ce que le cumul finisse par être significatif...

    Ma démarche serait donc de mettre l'avancement et le AddToBdd en commentaire. J'espère qu'à ce stade on ne verra plus de différence significative entre une exécution en avant/arrière plan. On peut alors réincorporer le traitement complet AddToBdd et tester (à priori je pense pas de différence) puis l'avancement et tester (et je pense que là on va revoir une différence).

    Si c'est bien l'avancement comme je le soupçonne, je suggère généralement de faire un test pour ne pas signaler la progression si il n'y a rien de significatif (par exemple garder en mémoire le dernier pourcentage signalé ou le dernier moment où cela a eu lieu et ne mettre à jour l'interface que si le pourcentage a bougé ou si un peu de temps s'est écoulé). Accessoirement l'application doit également être actuellement peu réactive (car on appelle la mise à jour sur le thread UI trop fréquemment et donc le thread UI est occupé en permanence ce qui est justement ce qu'on voulait éviter en faisant un traitement d'arrière plan) et cette approche va aussi rendre le thread UI plus réactif (appeler le thread UI trop fréquemment est sans doute l'erreur la plus fréquente que je vois avec les traitements en arrière plan).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    jeudi 29 novembre 2012 19:23
    Modérateur
  • C'est exactement ce que j'ai fait comme tests : dans le cas d'un thread secondaire, voici les résultats de mes tests


    A noter : l'ajout en base de donnée ne se fait qu'une fois par fichier (la première fois qu'on le voit, et s'il est écrasé par un nouveau fichier), donc le gain que l'on peut constaté sur ce tableau n'est pas aussi important que ça....

    Je garde en tête l'idée de mettre à jour l'UI que lorsqu'il y a un changement de valeur, merci.

    • Modifié Morphée jeudi 29 novembre 2012 23:10
    jeudi 29 novembre 2012 23:02
  • ReBonjour

    J’ai testee aussi, System.Diagnostics.Process.GetCurrentProcess().PriorityClass s’applique pour toute l’application. 

    Est-il possible d’essayer de trouver une autre solution pour vérifier si le fichier est utilisé oui en cours de copie ?

    Au moins sur le réseau c’est sûr que c’est une opération couteuse comme temps.

     Je vous propose ca :

    static bool FileInUse(string path)

        {

            try

            {

                using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))

                {

                    fs.CanWrite

                }

                return false;

            }

            catch (IOException ex)

            {

                return true;

            }

        }

     Cordialement,


    Aurel BERA, Microsoft
    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.

    J'ai traduit et testé comme cela :

    Function IsFileAvaible(ByVal FilePath As String) As Boolean
            Try
                Using fs As New FileStream(FilePath, FileMode.OpenOrCreate)
                    Return fs.CanWrite
                End Using
            Catch ex As Exception
                Return False
            End Try
        End Function
    Mais ça ne fonctionne pas
    mardi 4 décembre 2012 09:51
  • Je l'ai testée aussi et il retourne toujours True.

    Donc on ne peut pas utiliser ça.

    Justement pour vérifier les temps, mettez  Backgroundworker.WorkerReportsProgress = false ; et n’utilisez pas   worker.ReportProgress. 

    J’aimerai savoir le temps gagnée comme ça.

    Aurel.


    Aurel BERA, Microsoft
    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.

    mercredi 5 décembre 2012 14:24
  • J'ai du mal à lire cette tripotée de résultat (on dirait que la combinaison "data crea dans la boucle", "mise à jour ui" et "fichier sur réseau" propulse au delà des 4 min alors que les autres cas sont plus rapides).

    A mon avis inutile de faire varier trop de choses ou de tester trop de cas de figures à la fois. Comme je disais, mon approche serait plutôt de faire un cas simple qui me donnerait un même temps entre un traitement d'avant plan et d'arrière plan (je crois voir que vous avez une telle situation dans le tableau ci-dessus ?) puis d'incorporer les autres éléments dont j'ai besoin un par un en testant à chaque fois et en analysant la situation dès que 1) le temps augmente significativement ou 2) une différence importante entre les deux traitements apparait.

    Egalement tester au moins deux fois (dans mon test, la table des fichiers monte visiblement en mémoire sur une clé USB et donc le premier traitement qu'il soit en avant ou arrière plan est forcément plus long).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    mercredi 5 décembre 2012 14:57
    Modérateur
  • Alors, pour simplifier je reprends : j'ai laissé tombé le backgroundworker, je fais des tests avec un thread et le code suivant pour exemple : c'est très simple, avec un bouton on lance la fonction testsub dans le thread principal, avec l'autre bouton on lance la fonction dans le thread "Threading.Thread", et j'obtiens des résultats différents... (cf ci-dessus)

    Sub testsub()
            Dim test As String = ""
            Dim count_avancement As Integer = 0
            For indexfile = 0 To 13300
                Application.DoEvents()
                Try
                    Dim DateCreation As Date = FileDateTime("C:\Users\NAME\Desktop\test.txt")
                    Dim DiffDate As Integer = DateDiff(DateInterval.Minute, DateCreation, Now)
                    count_avancement += 1
                    test = test & "C:\Users\NAME\Desktop\Nom_du_fichier.ext" & ";"
                    AddToBdd("C:\Users\NAME\Desktop\Nom_du_fichier.ext", "1", DateCreation.ToString("yyyy-MM-dd H:mm:ss"))
                    SetLabelText_ThreadSafe(Me.LabelUI, CInt(count_avancement * 100 / (Max(13300, count_avancement) + 2)) & "%")
                    SetPBValue_ThreadSafe2(Me.UIProgressBar, count_avancement * 100 / (13300 + 2))
                Catch ex As Exception
    
                End Try
    
            Next
            SetLabelText_ThreadSafe(Me.LabelUI, "100%")
    End Sub
    
    ' The delegate
    Delegate Sub SetPBValue_Delegate2(ByVal [PB] As ProgressBar, ByVal [value] As Integer)
    ' The delegates subroutine.
    Private Sub SetPBValue_ThreadSafe2(ByVal [PB] As ProgressBar, ByVal [value] As Integer)
            Dim pourcent As Integer = [value]
            If pourcent > 100 Then
                pourcent = 100
            ElseIf pourcent < 0 Then
                pourcent = 0
            End If
    
            ' InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread.
            ' If these threads are different, it returns true.
            If [PB].InvokeRequired Then
                Dim MyDelegate As New SetPBValue_Delegate2(AddressOf SetPBValue_ThreadSafe2)
                Me.Invoke(MyDelegate, New Object() {[PB], pourcent})
            Else
                [PB].Value = pourcent
            End If
    End Sub
    
    'Bouton de test avec thread secondaire
    Private Sub TestButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TestButton.Click
            SetLabelText_ThreadSafe(Me.LabelUI, "0%")
            testThread.Abort()
            testThread = New Threading.Thread(AddressOf testsub)
            UIProgressBar.Value = 0
            UIProgressBar.Visible = True
            LabelUI.Text = "Refreshing list"
            testThread.Start()
            testThread.IsBackground = True
     End Sub
    
    'Bouton de test avec thread principal
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            testsub()
    End Sub

    mercredi 5 décembre 2012 15:07
  • Et donc sans indiquer l'avancement cela donne quoi ? Comme je l'avais indiqué plus haut la différence que je vois sur ce code est que en avant plan on mets à jour directement l'UI tandis qu'en arrière plan on va faire 26600 "invoke" en plus pour passer d'une thread à l'autre (2 à chaque boucle) et j'avais déjà suggéré de faire le même test en mettant en commentaire les lignes :

     SetLabelText_ThreadSafe(Me.LabelUI, CInt(count_avancement * 100 / (Max(13300, count_avancement) + 2)) & "%")
     SetPBValue_ThreadSafe2
    (Me.UIProgressBar, count_avancement * 100 / (13300 + 2))

    Indiquez également SVP les mesures concrètes que l'on puisse se faire une idée de la différence. Si la différence disparait c'est bien que l'on appellle trop souvent la thread UI depuis le thread d'arrière plan comme je l'avais suggéré dans ma première réponse.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    • Marqué comme réponse Morphée jeudi 6 décembre 2012 11:06
    mercredi 5 décembre 2012 16:03
    Modérateur
  • Effectivement ça change pas mal de choses de commenter les fonctions d'avancement.

    Merci Patrice !

    Pour ceux qui veulent tout de même suivre l'avancement du thread secondaire j'ai suivi les conseils et fait une fonction qui ne met à jour que si nécessaire :

        Sub ReportListingProgress(ByVal NbFileListed As Integer)
            Dim pourcent As Integer = NbFileListed * 99 / Max(NbFileListed, MediaTab.Length)
            If pourcent > 100 Then
                pourcent = 100
            ElseIf pourcent < 0 Then
                pourcent = 0
            End If
            If pourcent <> MediaProgressBar.Value Then
                SetLabelText_ThreadSafe(Me.LabelMedia, pourcent & "%")
                SetPBValue_ThreadSafe(Me.MediaProgressBar, pourcent)
            End If
        End Sub

    jeudi 6 décembre 2012 11:06
  • Merci à tous, je pense qu'entre l'optimisation du code et le meilleur management de l'avancement dans l'UI j'ai de bien meilleures perf.

    Pour info, je pense encore diviser par 2 le nombre d'invoke en réunissant les 2 fonctions threadsafe....
    jeudi 6 décembre 2012 15:09