Threading et événements Windows Forms - ListBox se met à jour rapidement mais la barre de progression connaît un retard énorme

StackOverflow https://stackoverflow.com/questions/12095

Question

Notre équipe crée un nouveau système de workflow de recrutement pour remplacer l'ancien.J'ai été chargé de migrer les anciennes données vers le nouveau schéma.J'ai décidé de le faire en créant un petit projet Windows Forms car les schémas sont radicalement différents et les scripts TSQL simples ne sont pas une solution adéquate.

La classe principale scellée « ImportController » qui effectue le travail déclare l'événement délégué suivant :

public delegate void ImportProgressEventHandler(object sender, ImportProgressEventArgs e);
public static event ImportProgressEventHandler importProgressEvent;

La fenêtre principale démarre une méthode statique dans cette classe en utilisant un nouveau thread :

Thread dataProcessingThread = new Thread(new ParameterizedThreadStart(ImportController.ImportData));
dataProcessingThread.Name = "Data Importer: Data Processing Thread";
dataProcessingThread.Start(settings);

les arguments ImportProgressEvent transportent un message de chaîne, une valeur int maximale pour la barre de progression et une valeur int de progression actuelle.Le formulaire Windows s'abonne à l'événement :

ImportController.importProgressEvent += new ImportController.ImportProgressEventHandler(ImportController_importProgressEvent);

Et répond à l'événement de cette manière en utilisant son propre délégué :

    private delegate void TaskCompletedUIDelegate(string completedTask, int currentProgress, int progressMax);

private void ImportController_importProgressEvent(object sender, ImportProgressEventArgs e)
            {
                this.Invoke(new TaskCompletedUIDelegate(this.DisplayCompletedTask), e.CompletedTask, e.CurrentProgress, e.ProgressMax);
            }

Enfin la barre de progression et la listbox sont mises à jour :

private void DisplayCompletedTask(string completedTask, int currentProgress, int progressMax)
        {
            string[] items = completedTask.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string item in items)
            {
                this.lstTasks.Items.Add(item);
            }

            if (currentProgress >= 0 && progressMax > 0 && currentProgress <= progressMax)
            {
                this.ImportProgressBar.Maximum = progressMax;
                this.ImportProgressBar.Value = currentProgress;
            }
        }

Le problème est que la ListBox semble se mettre à jour très rapidement, mais de toute façon, la barre de progression ne bouge jamais jusqu'à ce que le lot soit presque terminé ???ce qui donne ?

Était-ce utile?

La solution 4

@John

Merci pour les liens.

@Volonté

Il n'y a aucun gain à tirer du pooling de threads car je sais qu'il ne générera qu'un seul thread.L'utilisation d'un thread vise uniquement à avoir une interface utilisateur réactive pendant que SQL Server est soumis à des lectures et des écritures.Ce n'est certainement pas un fil de discussion éphémère.

Concernant les marteaux, vous avez raison.Mais il s’avère que mon problème se situait après tout entre l’écran et la chaise.Il me semble avoir un lot de données inhabituel qui contient beaucoup plus d'enregistrements de clé étrangère que les autres lots et qui se trouve être sélectionné au début du processus, ce qui signifie que le currentProgress n'est pas ++ pendant 10 bonnes secondes.

@Tous

Merci pour toutes vos contributions, cela m'a fait réfléchir, ce qui m'a fait chercher ailleurs dans le code, ce qui a conduit à mon ahaa moment d'humilité où je prouve encore une fois que l'erreur est généralement humaine :)

Autres conseils

Peut-être en dehors du cadre mais, parfois, il est utile de faire une Application.DoEvents(); pour faire réagir les parties de l'interface graphique aux entrées de l'utilisateur, par exemple en appuyant sur le bouton Annuler dans une boîte de dialogue de la barre d'état.

Est-ce que par hasard vous utilisez Windows Vista ?J'ai remarqué exactement la même chose dans certaines applications liées au travail.D'une manière ou d'une autre, il semble y avoir un délai lorsque la barre de progression "s'anime".

Êtes-vous sûr que le thread de l'interface utilisateur s'exécute librement pendant tout ce processus ?c'est à dire.il n'est pas bloqué lors d'une jointure ou d'une autre attente ?C'est à ça que ça me ressemble.

La suggestion d'utiliser BackgroundWorker est une bonne idée - certainement supérieure à celle d'essayer de vous sortir du problème avec une charge d'appels d'actualisation/mise à jour.

Et BackgroundWorker utilisera un thread de pool, ce qui est une manière plus conviviale de se comporter que de créer votre propre thread de courte durée.

Il n'y a pas de gain de Threadpooling car je sais qu'il n'apparaîtra qu'un thread.L'utilisation d'un thread est purement pour avoir une interface utilisateur réactive tandis que SQL Server est pilée avec des lectures et des écritures.Ce n'est certainement pas un fil de courte durée.

OK, j'apprécie cela et je suis heureux que vous ayez trouvé votre bug, mais avez-vous regardé BackgroundWorker ?Il fait à peu près exactement ce que vous faites, mais de manière standardisée (c'est-à-diresans vos propres délégués) et sans avoir besoin de créer un nouveau fil de discussion - deux avantages (peut-être petits, mais peut-être quand même utiles).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top