HttpWebRequest的并发限制

9
我正在使用C#编写一个应用程序来测量我下载网页的速度。我提供了一个唯一域名列表,然后生成X个线程并执行HTTPWebRequests,直到域名列表被消耗完。问题是,无论我使用多少个线程,我只能得到大约3个页面每秒。
我发现System.Net.ServicePointManager.DefaultConnectionLimit是2,但我认为这与每个域的连接数有关。由于列表中的每个域都是唯一的,这不应该是问题。
然后我发现GetResponse()方法会阻止其他进程访问,直到WebResponse被关闭:http://www.codeproject.com/KB/IP/Crawler.aspx#WebRequest,我没有找到任何其他支持这种说法的信息,但我使用套接字实现了一个HTTP请求,并注意到了显着的加速(4倍至6倍)。
所以我的问题是:有人知道HttpWebRequest对象的工作原理吗?除了上面提到的方法之外,还有解决方法吗?或者有没有用C#编写的高速网络爬虫的例子?

您可以配置每个域的连接限制,但默认情况下连接限制是全局的。https://msdn.microsoft.com/zh-cn/library/fb6y0fyc.aspx - Kind Contributor
3个回答

8

你尝试使用异步方法例如BeginGetResponse()了吗?

如果你正在使用.NET 4.0,你可以尝试以下代码。基本上我使用Tasks在特定的网站上进行1000次请求(我使用这个来测试我的应用在开发机上的负载能力,由于我的应用程序正在快速连续地发送这些请求,我没有看到任何限制)。

  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      for (int i = 0; i < 1000; i++)
      {
        var webRequest = WebRequest.Create(textBox1.Text);
        webRequest.GetReponseAsync().ContinueWith(t =>
        {
          if (t.Exception == null)
          {
            using (var sr = new StreamReader(t.Result.GetResponseStream()))
            {
              string str = sr.ReadToEnd();
            }
          }
          else
            System.Diagnostics.Debug.WriteLine(t.Exception.InnerException.Message);
        });
      }
    }
  }

  public static class WebRequestExtensions
  {
    public static Task<WebResponse> GetReponseAsync(this WebRequest request)
    {
      return Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
    }
  }

由于此处的工作负载是I/O绑定的,因此不需要生成线程来完成任务,实际上这样做可能会损害性能。使用WebClient类上的异步方法使用I/O完成端口,因此将更具性能且资源消耗较少。


3

您应该使用不会阻塞且是异步的BeginGetResponse方法。

在处理I/O绑定异步操作时,即使您启动一个线程来执行I/O工作,该线程仍将被阻塞等待硬件(在本例中为网络卡)响应。如果使用内置的BeginGetResponse,则该线程将只是将其排入网络卡队列中,并且随后可用于执行更多工作。当硬件完成时,它将通知您,此时将调用您的回调函数。


1

我想指出BeginGetResponse方法并不完全是异步的:(来自MSDN

BeginGetResponse方法需要一些同步设置任务完成(例如DNS解析、代理检测和TCP套接字连接),然后该方法才变成异步。因此,这个方法不应该在用户界面(UI)线程上调用,因为它可能需要一些时间,通常需要几秒钟。


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