Domanda

I Attualmente lavorando Un'applicazione che legge da un file binario grande, che contiene diversi file di migliaia, ogni file viene elaborato da qualche altra classe in applicazione.Questa classe restituisce un oggetto o null.Voglio mostrare un progresso sulla forma principale, ma per qualche motivo non riesco a farne la testa.

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);
.

Il codice sopra blocca il mio modulo, anche io uso "Taskscheduler.fromCurrentsynchronizationContext", perché?Perché quando utilizzo il codice sotto i miei aggiornamenti del modulo Fine

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);           
    }
});
.

Sono nuovo a questo intero TPL DataFlow, quindi spera che qualcuno possa condividere un po 'di luce sul perché nel secondo codice Snippet funziona e nel primo snippet no.

Cordiali saluti, Martijn

È stato utile?

Soluzione

Il motivo per cui il tuo utente è bloccato è becase stai usando FromCurrentSynchronizationContext. Fa funzionare il codice sulla filettatura dell'interfaccia utente, il che significa che si congelerà se si effettua una lunga azione da corsa (molto probabilmente GetFileFromLargeFile()).

D'altra parte, è necessario eseguire il lblProgress.Text sul filo UI.

Non sono sicuro che dovresti impostare lblProgress.Text direttamente in questo codice, assomiglia a un accoppiamento troppo stretto a me. Ma se vuoi farlo, penso che dovresti correre solo quella linea sul filo UI:

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);
    }
});
.

Ma una soluzione ancora migliore sarebbe se hai effettuato GetFileFromLargeFile() asincrono e assicurati che non faccia alcuna azione di lunga durata sulla filettatura dell'interfaccia utente ( ConfigureAwait(false) può aiutarti con questo). Se lo hai fatto, il codice del ActionBlock potrebbe funzionare sulla discussione dell'interfaccia utente senza congelare il tuo UI:

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);
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top