2012-07-02 10 views
5

Funcionalmente tiene una larga lista de palabras vinculadas a un ListView. Use un TextBox para caracteres para filtrar la lista de palabras.Cómo cancelar cualquier actual Paralelo.ParaEach y comenzar Fresco

Con cualquier nuevo carácter, debe cancelar cualquier filtro de fondo de procesamiento. A continuación, espere 1 segundo (DispatcherTimer) para iniciar un nuevo filtro paralelo de fondo.

Haga que esto funcione usando BackGroundWorker pero no puede traducir la parte cancelar-cualquier-proceso a Paralelo. Básicamente necesita "if (backgroundWorkerFTSfilter.IsBusy) backgroundWorkerFTSfilter.CancelAsync();" en paralelo.
Si voy por este error, por favor avíseme.

private List<FTSword> fTSwordsFiltered = new List<FTSword>(); 
CancellationTokenSource ftsCts = new CancellationTokenSource(); 
ParallelOptions ftspo = new ParallelOptions(); 
// in ctor ftspo.CancellationToken = ftsCts.Token; 

public List<FTSword> FTSwordsFiltered // ListView bound to 
{ 
    get { return fTSwordsFiltered; } 
    set 
    { 
     if (fTSwordsFiltered == value) return; 
     fTSwordsFiltered = value; 
     NotifyPropertyChanged("FTSwordsFiltered"); 
    } 
} 
public string FTSwordFilter   // TextBox bound to 
{ 
    get { return fTSwordFilter; } 
    set 
    { 
     if (value == fTSwordFilter) return; 

     fTSwordFilter = value; 
     NotifyPropertyChanged("FTSwordFilter"); 

     // cancel any filter currently processing 
     ftsCts.Cancel(); // fts filter    
     // with BackgroundWorker this was able to cancel    
     // if (backgroundWorkerFTSfilter.IsBusy) backgroundWorkerFTSfilter.CancelAsync(); 

     dispatcherTimerFTSfilter.Stop(); 
     // wait 1 second and apply filter in background 
     dispatcherTimerFTSfilter.Start(); 
    } 
} 
private void dispatcherTimerFTSfilter_Tick(object sender, EventArgs e) 
{ 
    dispatcherTimerFTSfilter.Stop(); 
    List<FTSword> ftsWords = new List<FTSword>(); 
    //ftsCts = new CancellationTokenSource(); with these two it never cancels 
    //ftspo.CancellationToken = ftsCts.Token; 
    if (!(string.IsNullOrEmpty(FTSwordFilter))) 
    { 
     Task.Factory.StartNew(() => 
     { 

      try 
      { 
       Parallel.ForEach(FTSwords, ftspo, ftsw => 
       { 
        if (ftsw.WordStem.StartsWith(FTSwordFilter)) 
        { 
         ftsWords.Add(ftsw); 
        } 
        ftspo.CancellationToken.ThrowIfCancellationRequested(); 
       }); 
       Thread.Sleep(1000); // so the next key stoke has time 
       FTSwordsFiltered = (List<FTSword>)ftsWords; 
      } 
      catch (OperationCanceledException ei) 
      { 
       // problem is that it is always cancelled from the cancel request before DispatchTimer 
       Debug.WriteLine(ei.Message); 
      } 
      Debug.WriteLine(ftsWords.Count.ToString() + "parallel "); 
     });   
    } 
} 

La respuesta de Irman me llevó a este

if (!(string.IsNullOrEmpty(FTSwordFilter))) 
    { 
     string startWorkFilter = FTSwordFilter; 
     Task.Factory.StartNew(() => 
     { 
      try 
      { 
       fTSwordsFilteredCancel = false; 
       Parallel.ForEach(FTSwords, ftspo, (ftsw, loopstate) => 
       { 
        if (ftsw.WordStem.StartsWith(startWorkFilter)) 
        { 
         ftsWords.Add(ftsw); 
        } 
        // Thread.Sleep(1); 
        if (fTSwordsFilteredCancel) 
        { 
         loopstate.Break(); 
        } 
       }); 
       Debug.WriteLine("fTSwordsFilteredCancel " + fTSwordsFilteredCancel.ToString()); 
       FTSwordsFiltered = (List<FTSword>)ftsWords; 
       Debug.WriteLine(ftsWords.Count.ToString() + " parallel " + startWorkFilter);      
      } 
      catch (OperationCanceledException ei) 
      { 
       Debug.WriteLine(ei.Message); 
      } 
     }); 
    } 

muy agradecidos por la respuesta que yo y utilizará esto para algunas tareas ya en ejecución o lista más larga, pero tiene tan gran rendimiento Moví esto a la get (aún con un retraso de 1 segundo). Resultados en una huella de memoria más pequeña. Contra 800,000 se ejecuta en menos de 1/10 de segundo.

public IEnumerable<FTSword> FTSwordsFiltered 
{ 
    get 
    { 
     if(string.IsNullOrEmpty(FTSwordFilter) || FTSwordFilter == "*") return FTSwords; 
     return FTSwords.AsParallel().Where(ftsWrd => ftsWrd.WordStem.StartsWith(FTSwordFilter)); 
    } 

Respuesta

5

Parallel.ForEach viene con el objeto ParallelLoopState. puedes usar este objeto para romper el ciclo.

puede usar loopState.Break() o loopState.Stop() en función de sus requisitos.

comprobar esto.

http://msdn.microsoft.com/en-us/library/dd991486.aspx

+0

Por favor marque lo que creo que es el uso correcto de loopState.Break() antes me marca como respondida. (La versión paralela era tan rápida que tuve que dormir en el Parallel.ForEach para incluso tener tiempo para cancelar) – Paparazzi

+0

Se ve bien. Si no desea utilizar el token de cancelación, puede eliminar el objeto de opción paralelo aprobado en la llamada Parallel.ForEach. BTW - ParallelOption también se utiliza para limitar el número de procesadores utilizados para ejecutar esta llamada. –

+0

En el ctor configuré el ftspo.MaxDegreeOfParallelism = System.Environment.ProcessorCount; para mantener las cosas restringidas. – Paparazzi

Cuestiones relacionadas