6

我正在开发一个基于 .NET4 的应用程序,它必须请求第三方服务器才能从它们那里获取信息。我正在使用 HttpClient 发出这些 HTTP 请求。

我必须在短时间内创建一百或一千个请求。我想将这些请求的创建限制在一个限制(由常量或其他东西定义),这样其他服务器就不会收到很多请求。

我已经检查了这个链接,它显示了如何减少随时创建的任务数量。

这是我的非工作方法:

// 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 的方法。

我应该如何处理这种情况?我想将创建的请求数量限制在一定范围内,但不要阻止等待这些请求完成。

这可能吗?有任何想法吗?

4

4 回答 4

1

您可以考虑创建一个新的 DelegatingHandler 来放置在 HTTPClient 的请求/响应管道中,该管道可以计算待处理请求的数量。

通常使用单个 HTTPClient 实例来处理多个请求。与 HttpWebRequest 不同,释放 HttpClient 实例会关闭底层 TCP/IP 连接,因此如果要重用连接,则确实需要重用 HTTPClient 实例。

于 2012-12-04T13:33:48.977 回答
1

如果您可以使用 .Net 4.5,一种方法是使用TransformBlockTPL Dataflow 并设置其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同时启动所有 s,但实际上只有有限数量的 s 会做某事。虽然限制Tasks 的数量(例如,通过使用 TPL 数据流,正如我上面所建议的)将很可能更有效。

于 2012-11-29T18:38:30.183 回答
0

您可能会考虑启动一组固定的线程。每个线程串行执行客户端网络操作;可能还会在某些点暂停以进行节流。这将为您提供对加载的特定控制;您可以更改节流策略并更改线程数。

于 2012-11-29T04:25:51.357 回答
0

首先,您应该考虑根据网站对工作负载进行分区,或者至少公开一个抽象,让您选择如何对 url 列表进行分区。例如,一种策略可以是二级域,例如 yahoo.com、google.com。

另一件事是,如果您要进行认真的爬网,则可能要考虑在云上进行。这样,云中的每个节点都可以爬取不同的分区。当你说“短时间”时,你已经为失败做好了准备。你需要确定你想要达到的目标。

良好分区的另一个关键好处是,您还可以避免在高峰时段访问服务器并在其路由器级别冒 IP 禁令的风险,以防网站不简单地限制您。

于 2012-11-29T04:13:12.813 回答