1

我正在做一个项目,我需要加载多个(100 多个)远程 RSS 提要,解析它们并查询一些关键字。显然这个过程很耗时,我正在寻找实现这一点的最佳方法。

我当前的实现同步加载提要,因为 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;
                    }
                }
            }


        }

没有结果属性

4

2 回答 2

1

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

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

我建议的一件事是重用 HttpClient 类。总是为每个请求创建一个新实例似乎有点矫枉过正。

于 2013-04-18T21:12:11.753 回答
0

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

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

于 2013-04-18T22:22:54.460 回答