我正在开发一个基于.NET4的应用程序,它必须请求第三方服务器才能从中获取信息。我正在使用HttpClient来发出这些HTTP请求。
我必须在短时间内创建一百或一千个请求。我想将这些请求的创建限制为一个限制(由常量或其他东西定义),以便其他服务器不会收到大量请求。
我已经检查了this link,显示了如何减少随时创建的任务量。
这是我的非工作方法:
// create the factory
var factory = new TaskFactory(new LimitedConcurrencyLevelTaskScheduler(level));
// use the factory to create a new task that will create the request to the third-party server
var task = factory.StartNew(() => {
return new HttpClient().GetAsync(url);
}).Unwrap();
当然,这里的问题是,即使创建了当时的一个任务,也会同时创建和处理大量请求,因为它们在另一个调度程序中运行。我找不到将调度程序更改为HttpClient的方法。
我该如何处理这种情况?我想将创建的请求数量限制为某个限制,但不要阻止等待这些请求完成。
这可能吗?有什么想法吗?
答案 0 :(得分:1)
如果您可以使用.Net 4.5,一种方法是使用TPL Dataflow中的TransformBlock
并设置其MaxDegreeOfParallelism
。类似的东西:
var block = new TransformBlock<string, byte[]>(
url => new HttpClient().GetByteArrayAsync(url),
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = level });
foreach (var url in urls)
block.Post(url);
block.Complete();
var result = new List<byte[]>();
while (await block.OutputAvailableAsync())
result.Add(block.Receive());
通过ServicePointManager
还有另一种方式来看待这个问题。使用该类,您可以在MaxServicePoints
(一次可以连接多少台服务器)和DefaultConnectionLimit
(每台服务器可以连接多少个连接)上设置限制。这样,您可以在同一时刻启动所有Task
,但实际上只有有限数量的Task
会执行某些操作。虽然限制{{1}}的数量(例如,通过使用TPL Dataflow,如上所述)将更有效。
答案 1 :(得分:1)
您可以考虑创建一个新的DelegatingHandler,使其位于HTTPClient的请求/响应管道中,该管道可以保留待处理请求数的计数。
通常,单个HTTPClient实例用于处理多个请求。与HttpWebRequest不同,处理HttpClient实例会关闭底层的TCP / IP连接,因此如果要重用连接,则需要重新使用HTTPClient实例。
答案 2 :(得分:0)
首先,您应该考虑根据网站对工作负载进行分区,或者至少公开一个抽象,让您选择如何对网址列表进行分区。例如,一种策略可以是二级域,例如yahoo.com,google.com。
另一件事是,如果您正在进行严重爬行,您可能需要考虑在云上进行。这样,云中的每个节点都可以抓取不同的分区。当你说“短时间”时,你已经为失败做好准备了。你想要达到的目标需要硬数字。
分区效果的另一个主要好处是,您还可以避免在高峰时段点击服务器,并在路由器级别冒着IP禁令的风险,如果该网站不能简单地限制您。
答案 3 :(得分:0)
您可以考虑启动一组固定的线程。每个线程串行完成客户端网络操作;也许在某些时候暂停以节流。这将为您提供对装载的具体控制;您可以更改限制策略并更改线程数。