我有一个URL列表,我必须调用它并做一些工作。这已经可以正常工作,但List很大,执行时间很长。
我认为我可以通过同时处理5个Url来加速程序,因为执行时间的很大一部分很可能是程序正在等待Urls服务器响应。
我有一个网址列表
List<string> urls = getmyurls();
然后我正在迭代它们
for (int i = 0; i < links.Count; i++)
{
List<string> result = dosomework(urls.ElementAt(i))
urls.AddRange(result);
}
有时我会收到一些必须处理的额外网址。
(代码就是一个例子,我的实际程序结构有点不同。这是解释我问题的最小例子。)
我想要的是同时运行“dosomework”功能的五个线程。每当其中一个完成时,我希望它从下一个URL开始。
另外:你会运行多少个线程?
答案 0 :(得分:1)
当您尝试解析URL并从网络中拔出时,它类似于从磁盘拉出或从数据库读取,因为这些都是I / O绑定操作。并行实际上是不可取的,因为更多的线程没有帮助,而是阻碍性能。您最好的选择是使用async
和await
关键字,假设您使用 .NET 4.5 。
有些人建议Parallel.ForEach
,但这最适合CPU绑定任务。对于I / O绑定任务,您需要Task.WhenAll
。
Here is great video demonstration作者:Jeffrey Richter。我强烈鼓励观看它。与此同时,我会编写你的迭代调用。
private static IEnumerable<string> GetUrls()
{
return new[] { "https://stackoverflow.com/", "http://www.google.com/" };
}
internal async Task Fetch()
{
var urls = GetUrls();
var tasks = urls.Select(DoWorkAsync);
await Task.WhenAll(tasks);
}
internal Task DoWorkAsync(string url)
{
// TODO: Implement actual work on the URL in an async manner.
return Task.FromResult(url);
}
这个想法是你可以获取URL,并从每个URL中选择一个在DoWorkAsync
上执行的任务。然后等待所有这些。
<强>更新强>
看起来似乎已经回答了限制here。
答案 1 :(得分:0)
我是TPL Dataflow library的粉丝。它完全符合这个用例,值得学习。
这是一个原始实现,向您展示它的工作原理。
var processURL = new TransformManyBlock<string, string>(url => {
return dosomework(url);
},
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5 });
var urls = getmyurls();
foreach(var url in urls)
processURL.Post(url);
processURL.Completion.Wait();
var results = processURL.Receive();
可以阅读流程管道的一个很好的例子here。
答案 2 :(得分:-1)
您正在寻找的可能是并行LINQ。
考虑https://msdn.microsoft.com/pl-pl/library/dd460714(v=vs.110).aspx
中的示例编辑:
在多个线程上运行时,添加WithDegreeOfParallelism(6)
,其中6是“线程”计数。这不完全是6个线程但是你想要的:)
在这里你有一个很好的解释:http://www.albahari.com/threading/part5.aspx
另外
ParallelOptions.MaxDegreeOfParallelism
指定最大并行级别