加载多个远程RSS源的最佳方法是什么?

时间:2013-04-18 19:22:48

标签: c# asynchronous rss task-parallel-library async-await

我正在开展一个项目,我需要加载多个(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;
                    }
                }
            }


        }

no result property

2 个答案:

答案 0 :(得分:1)

我在GitExtensions的分支中解决了类似的问题。我通过创建任务来调度8批REST API调用,并为每批8执行Task.WaitAll。它有点简单,但它可以在不使代码复杂化的情况下完成工作:

https://github.com/PombeirP/gitextensions/blob/BuildServerIntegration/Plugins/BuildServerIntegration/TeamCityIntegration/TeamCityAdapter.cs#L178

我建议的一件事是重用HttpClient类。总是为每个请求创建一个新实例看起来有点过分。

答案 1 :(得分:0)

恕我直言,当你遇到这样的问题时,最简单的方法是在输入集合上编写同步代码然后编写Parallel.ForEach。

它不像线程友好,但您可以非常简单地设置最大并行度,包括在调试期间将其设置为1。 :)