Question

Je travail en cours d'une application qui lit à partir d'un grand fichier binaire, qui est titulaire de plusieurs milliers de fichiers, chaque fichier est en cours de traitement par une autre classe dans l'application.Cette classe renvoie un objet ou la valeur null.Je veux montrer un progrès sur le formulaire principal, mais pour une raison que je ne peux pas obtenir ma tête autour de lui.

int TotalFound = 0;
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext;
BufferBlock<file> buffer = new BufferBlock<file>();
DataflowBlockOptions options = new DataflowBlockOptions(){ TaskScheduler = uiScheduler, }; 
var producer = new ActionBlock<someObject>(largeFile=>{ 
    var file = GetFileFromLargeFile(largeFile);
    if(file !=null){
       TotalFound++;
       buffer.post(file);
       lblProgress.Text = String.Format("{0}", TotalFound);
    }
}, options);

Le code ci-dessus se fige mon Formulaire, même dois-je utiliser "TaskScheduler.FromCurrentSynchronizationContext", pourquoi?Parce que quand j'utilise le code ci-dessous mes mises à jour des formulaires d'amende

DataflowBlockOptions options = new DataflowBlockOptions(){ TaskScheduler = uiScheduler, }; 
var producer = new ActionBlock<someObject>(largeFile=>{ 
    var file = GetFileFromLargeFile(largeFile);
    if(file !=null){
       Task.Factory.StartNew(() => {
          TotalFound++;
          buffer.Post(file);
       }).ContinueWith(uiTask => {
          lblProgress.Text = String.Format("{0}", TotalFound);
       },CancellationToken.None, TaskContinuationOptions.None, uiScheduler);           
    }
});

Je suis nouveau à tout ce TPL Dataflow, donc je suis en espérant que quelqu'un pourrait partager un peu de lumière sur pourquoi dans le deuxième extrait de code il fonctionne et dans le premier extrait, il ne le fait pas.

Cordialement, Martijn

Était-ce utile?

La solution

La raison de votre INTERFACE utilisateur est bloqué est becase vous êtes à l'aide de FromCurrentSynchronizationContext.Il provoque le code à exécuter sur le thread de l'INTERFACE utilisateur, ce qui signifie qu'il va geler si vous êtes en train de faire une longue action en cours d'exécution (le plus probable GetFileFromLargeFile()).

D'autre part, vous devez exécuter le lblProgress.Text sur le thread d'INTERFACE utilisateur.

Je ne suis pas sûr que vous devez définir lblProgress.Text directement dans ce code, il ressemble trop couplage étroit pour moi.Mais si vous voulez le faire, je pense que vous devriez exécuter juste cette ligne sur le thread de l'INTERFACE utilisateur:

var producer = new ActionBlock<someObject>(async largeFile =>
{
    var file = GetFileFromLargeFile(largeFile);
    if (file != null)
    {
        TotalFound++;
        await buffer.SendAsync(file);
        await Task.Factory.StartNew(
            () => lblProgress.Text = String.Format("{0}", TotalFound),
            CancellationToken.None, TaskCreationOptions.None, uiScheduler);
    }
});

Mais même la meilleure solution serait, si vous faites GetFileFromLargeFile() asynchrone et fait en sorte que ça ne fait pas long-actions en cours d'exécution sur le thread d'INTERFACE utilisateur (ConfigureAwait(false) peut vous aider avec ça).Si vous l'avez fait, le code de la ActionBlock peut s'exécuter sur le thread de l'INTERFACE utilisateur sans le gel de votre INTERFACE:

var producer = new ActionBlock<someObject>(async largeFile =>
{
    var file = await GetFileFromLargeFile(largeFile);
    if (file != null)
    {
        TotalFound++;
        await buffer.SendAsync(file);
        lblProgress.Text = String.Format("{0}", TotalFound)
    }
}, options);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top