3

我有这个示例代码。并行处理密集IO功能

List<Dictionary<string,string>> objects = new List<Dictionary<string,string>>(); 

foreach (string url in urls) 
{ 
    objects.add(processUrl(url)) 
} 

我需要处理的URL,processUrl下加载页面和运行许多正则表达式来提取一些信息,并返回一个“C#JSON像”对象,所以我想在平行,并在结束时运行这个我需要一个对象的列表,所以我需要等待所有的任务来继续过程,我该如何做到这一点?我举了很多例子,但都没有挽回回报。

问候

回答

2

是否这样?

var results = urls.AsParallel().Select(processUrl).ToList(); 

随着Parallel

Parallel.ForEach(
    urls, 
    url => 
    { 
     var result = processUrl(url); 
     lock (syncOjbect) 
      objects.Add(result); 
    }; 

var objects = new ConcurrentBag<Dictionary<string,string>>(); 
Parallel.ForEach(urls, url => objects.Add(processUrl(url))); 
var result = objects.ToList(); 

或任务:

var tasks = urls 
    .Select(url => Task.Factory.StartNew(() => processUrl(url))) 
    .ToArray(); 

Task.WaitAll(tasks); 
var restuls = tasks.Select(arg => arg.Result).ToList(); 
+1

我没有在Parallel.ForEach的主体中使用锁,而是使用具有localInit和localFinally的重载,并在localFinally中汇总所有结果。这样你就不会锁定每个操作,每个线程只有一次。在localInit中放置一个空列表,添加到本地而不锁定在主体中,并最终收集。 – vcsjones 2011-06-12 02:22:52

+0

这些选项都没有提供限制同时执行任务总数的方法。 – 2011-06-12 05:41:12

+0

@Rick Sladkey - 不知道我理解你的评论。所有3个选项都有一种方法来限制同时执行的任务的数量,我没有在代码中显示它,因为这没有被问到。 – 2011-06-12 05:53:56

0

首先,重构为

processUrl(url, objects); 

交任务负责添加结果到列表中。

然后添加锁定,这样两个并行任务不会尝试完全同时使用结果列表。


注:async在.NET的下一个版本的支持将让这个简单的。

+0

downvote的原因是什么? – 2011-06-12 02:42:34

-1

您可以使用PLINQ扩展,这需要.NET 4.0

System.Threading.Tasks.Parallel 
      .ForEach(urls, url => { 
      var result = processUrl(url); 
      lock(objects) 
      { 
        objects.Add(result); 
      } 
      }); 
+3

'列表'不是线程安全的。 – 2011-06-12 02:13:27

+3

只要物品处于类似列表的集合(例如数组或列表中),就可以使用Parallel.For。然后可以使用循环索引将结果输出到数组槽中。这将是线程安全的,不需要锁。 – bobbymcr 2011-06-12 02:21:51