C# - 如何同时进行多个网络请求

20

我写了一段检查网址的代码,但是非常慢...我想尝试让它同时处理几个网址,比如10个,或者至少尽可能地加快速度。

我的代码:

Parallel.ForEach(urls, new ParallelOptions {
  MaxDegreeOfParallelism = 10
}, s => {
  try {
    using(HttpRequest httpRequest = new HttpRequest()) {
      httpRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0";
      httpRequest.Cookies = new CookieDictionary(false);
      httpRequest.ConnectTimeout = 10000;
      httpRequest.ReadWriteTimeout = 10000;
      httpRequest.KeepAlive = true;
      httpRequest.IgnoreProtocolErrors = true;
      string check = httpRequest.Get(s + "'", null).ToString();
      if (errors.Any(new Func < string, bool > (check.Contains))) {
        Valid.Add(s);
        Console.WriteLine(s);
        File.WriteAllLines(Environment.CurrentDirectory + "/Good.txt", Valid);
      }
    }
  } catch {

  }
});

4
此外,只是顺便提一下,有些网络服务器可能不会并行处理您的请求(因为这可能看起来像DoS攻击,或者它仅限制来自IP的连接数量)。仅仅因为您并行发出10个请求,并不意味着网络服务器会并行返回数据给您。它可能仍然会将数据返回给您,就好像您按照发送请求->接收响应->发送->接收等方式发送它们一样。 - KSib
MaxDegreeOfParallelism 考虑到您机器的处理能力,而不是集合中记录的数量。如果您有双核处理器,它将同时处理 2 条记录。另一方面,浏览器可以并行发送更多请求,但服务器不行。 - Rohit Ramname
那我该如何让它更快呢?其他工具是如何做到快速的?即使是做同样事情的工具。 - Ariel
@RohitRamname 等待10个HTTP GET请求会消耗多少处理能力?让我猜猜:零? - Sir Rufo
@SirRufo,我也这么认为。我也需要解决这个问题的方案。 - Rohit Ramname
那么...我该怎么做才能让它运行得更快? - Ariel
2个回答

41

你的服务调用很可能不会受到CPU限制。因此,增加线程来处理负载可能不是最佳方案--如果可能的话,使用更现代的HttpClient而不是HttpRequest或HttpWebRequest,使用asyncawait可以获得更好的吞吐量。

这里是一个示例:

var client = new HttpClient();

//Start with a list of URLs
var urls = new string[]
    {
        "http://www.google.com",
        "http://www.bing.com"
    };

//Start requests for all of them
var requests  = urls.Select
    (
        url => client.GetAsync(url)
    ).ToList();

//Wait for all the requests to finish
await Task.WhenAll(requests);

//Get the responses
var responses = requests.Select
    (
        task => task.Result
    );

foreach (var r in responses)
{
    // Extract the message body
    var s = await r.Content.ReadAsStringAsync();
    Console.WriteLine(s);
}

谢谢,我会尝试一下。 - Ariel
3
这个能用于POST请求吗?如果可以的话,你能告诉我如何操作吗?谢谢。 - user5381191
由于某些原因,我一直遇到请求消息已经发送无法重新发送的问题。我创建了一个List<HttpRequestMessage>而不是string[],然后使用var requests = httpRequestMessages.Select(h => Client.SendAsync(h)) - user5381191
1
@HamzaKhanzada 听起来像是网络问题,或者可能是服务的问题;很可能与客户端代码无关。 - John Wu
1
@MichaelBrown 这个问题是关于发送多个请求,而不是发送一个带有多个文件的请求(这两者是很不同的)。我建议你另外发一个问题来询问。 - John Wu
显示剩余4条评论

-1

请尝试按照以下方式操作。

Parallel.ForEach(urls, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount - 1 }

至少这样可以确保所有的核心都在运行,留出1个核心来,这样您的计算机就不会因为内存不足而停止了。

此外,请考虑@KSib的评论。


谢谢你的答复,然而,当maxDegree=10时它运行得更快了。 - Ariel
你的代码片段缺失了一些部分,因此无法编译。 - Jan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接