如何取消任何当前的Parallel.ForEach并开始新鲜

时间:2012-07-02 19:32:12

标签: .net parallel.foreach

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

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

使用BackGroundWorker工作但不能将取消任意处理部分转换为并行。 基本上需要“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));
    }

1 个答案:

答案 0 :(得分:5)

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

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

检查一下。

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