【问题标题】:Parallel scraping in .NET.NET 中的并行抓取
【发布时间】:2014-04-09 12:16:48
【问题描述】:

我工作的公司经营着数百个非常活跃的网站。它决定建立一个搜索引擎,而我的任务是编写刮板。一些网站在旧硬件上运行,无法承受太多惩罚,而另一些则可以同时处理大量用户。

我需要能够说对站点 A 使用 5 个并行请求,对站点 B 使用 2 个并行请求,对站点 C 使用 1 个。

我知道我可以使用线程、互斥体、信号量等来完成此操作,但这会非常复杂。任何更高级别的框架(例如 TPL、await/async、TPL Dataflow)是否足够强大,可以以更简单的方式完成此应用程序?

【问题讨论】:

    标签: c# .net task-parallel-library async-await tpl-dataflow


    【解决方案1】:

    TPL Dataflowasync-await 确实强大且简单,足以满足您的需求:

    async Task<IEnumerable<string>> GetAllStringsAsync(IEnumerable<string> urls)
    {
        var client = new HttpClient();
        var bag = new ConcurrentBag<string>();
        var block = new ActionBlock<string>(
            async url => bag.Add(await client.GetStringAsync(url)),
            new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = 5});
        foreach (var url in urls)
        {
            block.Post(url);
        }
        block.Complete();
        await block.Completion;
        return bag;
    }
    

    【讨论】:

      【解决方案2】:

      我建议您使用HttpClientTask.WhenAll,以及SemaphoreSlim 进行简单的节流:

      private SemaphoreSlim _mutex = new SemaphoreSlim(5);
      private HttpClient _client = new HttpClient();
      private async Task<string> DownloadStringAsync(string url)
      {
        await _mutex.TakeAsync();
        try
        {
          return await _client.GetStringAsync(url);
        }
        finally
        {
          _mutex.Release();
        }
      }
      
      IEnumerable<string> urls = ...;
      var data = await Task.WhenAll(urls.Select(url => DownloadStringAsync(url));
      

      或者,您可以使用 TPL 数据流并设置 MaxDegreeOfParallelism 进行限制。

      【讨论】:

        猜你喜欢
        • 2011-05-05
        • 1970-01-01
        • 2023-03-25
        • 1970-01-01
        • 2021-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-27
        相关资源
        最近更新 更多