C# NET中的并行刮取

C# NET中的并行刮取,c#,.net,task-parallel-library,async-await,tpl-dataflow,C#,.net,Task Parallel Library,Async Await,Tpl Dataflow,我工作的公司经营着几百个非常有活力的网站。它已决定建立一个搜索引擎,我的任务是编写刮刀。一些网站运行在旧硬件上,无法承受太多惩罚,而另一些网站可以同时处理大量用户 我需要能够说,对站点A使用5个并行请求,对站点B使用2个并行请求,对站点C使用1个并行请求 我知道我可以使用线程、互斥体、信号量等来实现这一点,但这将非常复杂。像TPL、await/async、TPL Dataflow这样的高级框架是否足够强大,可以以更简单的方式运行此应用程序?我建议您将HttpClient与任务一起使用。Whall

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

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


我知道我可以使用线程、互斥体、信号量等来实现这一点,但这将非常复杂。像TPL、await/async、TPL Dataflow这样的高级框架是否足够强大,可以以更简单的方式运行此应用程序?

我建议您将
HttpClient
任务一起使用。Whalll
信号量lim
一起使用,以实现简单的节流:

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));
private SemaphoreSlim\u mutex=new SemaphoreSlim(5);
私有HttpClient _client=新HttpClient();
私有异步任务下载StringAsync(字符串url)
{
wait_mutex.TakeAsync();
尝试
{
返回wait_client.GetStringAsync(url);
}
最后
{
_mutex.Release();
}
}
IEnumerable URL=。。。;
var data=wait Task.WhenAll(url.Select(url=>DownloadStringAsync(url));

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

TPL数据流
async Wait
确实功能强大且简单,足以满足您的需要:

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;
}
异步任务GetAllStringsAsync(IEnumerable URL) { var client=新的HttpClient(); var bag=新的ConcurrentBag(); var block=新动作块( async url=>bag.Add(wait client.GetStringAsync(url)), 新的ExecutionDataflowBlockOptions{MaxDegreeOfParallelism=5}); foreach(url中的变量url) { block.Post(url); } block.Complete(); 等待区块完成; 返回袋; }