Как отменить любой текущий Parallel.ForEach и начать заново

Функционально иметь длинный список слов, привязанных к ListView. Используйте TextBox для символов, чтобы отфильтровать список слов.

С любым новым символом необходимо отменить любую обработку фонового фильтра. Затем подождите 1 секунду (DispatcherTimer ), чтобы запустить новый фоновый параллельный фильтр.

Пусть это работает с помощью BackGroundWorker, но не может преобразовать отмену -любую часть обработки -в Parallel. В основном нужно «if (backgroundWorkerFTSfilter.IsBusy )backgroundWorkerFTSfilter.CancelAsync ();» в параллели.
Если я делаю это неправильно, пожалуйста, дайте мне знать.

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

Ответ от Ирмана привел меня к этому

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

Очень благодарен за ответ. Я буду использовать его для некоторых более длительных задач или более длинного списка, но получил такую ​​​​отличную производительность, что переместил это в get (все еще с задержкой в ​​1 секунду ). Приводит к меньшему объему памяти. Против 800 000 он работает менее чем за 1/10 секунды.

public IEnumerable<FTSword> FTSwordsFiltered
{
    get 
    { 
        if(string.IsNullOrEmpty(FTSwordFilter) || FTSwordFilter == "*") return FTSwords; 
        return FTSwords.AsParallel().Where(ftsWrd => ftsWrd.WordStem.StartsWith(FTSwordFilter));
    }
5
задан paparazzo 3 July 2012 в 14:43
поделиться