0

这是我获取IEnumerable<string> source和搜索此路径中所有文件的函数:

public void search()
{
    Task.Factory.StartNew(() =>
    {
        try
        {
            Parallel.ForEach(_source,
            new ParallelOptions
           {
               MaxDegreeOfParallelism = 5 //limit number of parallel threads here 
           },
        file =>
        {
            FileChecker fileChecker = new FileChecker();
            string result = fileChecker.check(file);
            if (result != null)
                OnFileAddEvent(result);
        });
        }
        catch (Exception)
        { }

    }).ContinueWith
        (t =>
        {
            OnFinishSearchEvent();
        }
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}

  public void search2()
{
    Task.Factory.StartNew(() =>
    {
        var filtered = _source.AsParallel()
                                   .WithDegreeOfParallelism(5)
                                   .Where(file =>
                                   {
                                       try
                                       {
                                           FileChecker fileChecker = new FileChecker();
                                           string result = fileChecker.check(file);
                                           if (result != null)
                                               OnFileAddEvent(result);
                                           return true;
                                       }
                                       catch (Exception)
                                       {
                                           return false;
                                       }
                                   });
        return filtered.ToList();
    }).ContinueWith
     (t =>
     {
         OnFinishSearchEvent();
     }
     , TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
     );
}
4

2 回答 2

2

看起来您对多线程和异常处理有一个基本的误解。

.net 中的异常处理通常从抛出托管异常开始。然后,这会导致 .net VM 沿着调用堆栈向上走,直到找到合适的 try catch 块。

在这种情况下,Task.Factory.StartNew(Action), 是一个包装器,用于推送到Action委托中描述的线程池工作。在这种情况下,调用堆栈的顶部将是Action...中描述的委托

file =>
      {
            // check my file before adding to my Listbox
      }

因此,当异常冒泡时……调用堆栈不会“向上”捕获它。

然后,解决方案是,正如其他人所描述的那样,在您传递给Task.Factory.StartNew(Action)方法的委托中添加根级别的 try catch。

更一般地说,通常会在Task返回的 OnError 上添加一个继续Task.Factory.StartNew(Action)......但是我还要补充一点,我担心整个方法存在很大缺陷,因为没有一个工作线程应该能够添加到ListBox. 只能由构造它的ListBoxSTA 线程访问。

最终我会将整个方法更改为以下...

public void search()
{
   Task.Factory.StartNew(() =>
   {

        var filtered = source.AsParallel()
                                   .WithDegreeOfParallelism(5)
                                   .Where(file =>
        {
            try
            {
                //Some filter function...
            }
            catch(Exception)
            {
                return false;
            }
        });
        return filtered.ToList();
    }).ContinueWith
    (t =>
    {
        foreach(var result in t.Result)
        {
            MyListBox.Add(result);
        }
        OnFinishSearchEvent();
    }
    , TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
    );


}
于 2013-06-24T10:15:34.207 回答
0

您必须捕获任务内部的内容:

public void search()
{
    try
    {
        Task.Factory.StartNew(() =>
        {
            try{
            Parallel.ForEach(source,
                             new ParallelOptions
                             {
                                 MaxDegreeOfParallelism = 5 //limit number of parallel threads here 
                             },
                             file =>
                             {
                                // check my file before adding to my Listbox
                             });
            }).ContinueWith
                (t =>
                {
                    OnFinishSearchEvent();
                }
        , TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
        );
        catch(Exception ex){

        }
    }
    catch (Exception ex)
    {

    }
}
于 2013-06-24T10:06:14.583 回答