我正在开展一个项目,我需要加载多个(100多个)远程RSS源,解析它们并查询一些关键字。 显然这个过程非常耗时,我正在寻找实现这个目标的最佳方法。
我当前的实现同步加载了feed,因为使用TPL的异步实现失败了,因为在进程中创建了很多任务,最后它抛出了异常。
加载远程供稿的异步部分如下所示:
/// <summary>
/// Loads the specified URL.
/// </summary>
/// <param name="url">The URL.</param>
/// <returns></returns>
/// <exception cref="ScanException">Unable to download rss feed from the specified url. Check the inner exception for more details.</exception>
protected async Task<XDocument> Load(string url)
{
XDocument document = null;
try
{
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
document = XDocument.Parse(content);
}
}
}
catch (Exception ex)
{
throw new ScanException(url, "Unable to download rss feed from the specified url. Check the inner exception for more details.", ex);
}
return document;
}
我希望你们能指出我正确的方向,所以我可以让这个工作正常(表现明智)。
最后一个问题是:加载多个远程RSS源的最佳方法是什么?
测试代码
/// <summary>
/// Reads the feeds by batch async.
/// </summary>
/// <param name="feeds">The feeds.</param>
public void ReadFeedsByBatchAsync(string[] feeds, TorrentStorage storage, int batchSize = 8)
{
var tasks = new List<Task>(batchSize);
var feedsLeft = feeds.Length;
foreach (string feed in feeds)
{
var readFeedTask = this.client.GetStringAsync(feed);
if (readFeedTask.Status == TaskStatus.RanToCompletion)
{
XDocument document = XDocument.Parse(readFeedTask.Result);
var torrents = ProcessXmlDocument(document);
storage.Store(torrents);
}
tasks.Add(readFeedTask);
--feedsLeft;
if (tasks.Count == tasks.Capacity || feedsLeft == 0)
{
var batchTasks = tasks.ToArray();
tasks.Clear();
try
{
Task.WaitAll(batchTasks);
}
catch (Exception)
{
throw;
}
}
}
}
答案 0 :(得分:1)
我在GitExtensions的分支中解决了类似的问题。我通过创建任务来调度8批REST API调用,并为每批8执行Task.WaitAll。它有点简单,但它可以在不使代码复杂化的情况下完成工作:
我建议的一件事是重用HttpClient类。总是为每个请求创建一个新实例看起来有点过分。
答案 1 :(得分:0)
恕我直言,当你遇到这样的问题时,最简单的方法是在输入集合上编写同步代码然后编写Parallel.ForEach。
它不像线程友好,但您可以非常简单地设置最大并行度,包括在调试期间将其设置为1。 :)