5

从功能上讲,有一长串单词绑定到 ListView。使用 TextBox for chars 过滤单词列表。

使用任何新的 char 需要取消任何处理背景过滤器。然后等待 1 秒 (DispatcherTimer) 以启动新的后台并行过滤器。

使用 BackGroundWorker 进行此工作,但无法将 cancel-any-processing 部分转换为 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 ");
        });           
    }
}

Irman 的回答使我想到了这一点

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

1 回答 1

5

Parallel.ForEach 带有 ParallelLoopState 对象。你可以使用这个对象来打破循环。

您可以使用loopState.Break()loopState.Stop()根据您的要求。

检查这个。

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

于 2012-07-02T19:51:45.920 回答