C# HttpWebRequest上的并发限制

C# HttpWebRequest上的并发限制,c#,.net,multithreading,httpwebrequest,httpwebresponse,C#,.net,Multithreading,Httpwebrequest,Httpwebresponse,我正在编写一个应用程序来衡量使用C#下载网页的速度。我提供一个唯一域名列表,然后生成X个线程并执行HTTPWebRequests,直到域列表被使用为止。问题是,无论我使用多少线程,我每秒只能得到大约3页 我发现System.Net.ServicePointManager.DefaultConnectionLimit是2,但我觉得这与每个域的连接数有关。因为列表中的每个域都是唯一的,所以这不应该是一个问题 然后我发现GetResponse()方法会阻止来自所有其他进程的访问,直到WebRespon

我正在编写一个应用程序来衡量使用C#下载网页的速度。我提供一个唯一域名列表,然后生成X个线程并执行HTTPWebRequests,直到域列表被使用为止。问题是,无论我使用多少线程,我每秒只能得到大约3页

我发现System.Net.ServicePointManager.DefaultConnectionLimit是2,但我觉得这与每个域的连接数有关。因为列表中的每个域都是唯一的,所以这不应该是一个问题

然后我发现GetResponse()方法会阻止来自所有其他进程的访问,直到WebResponse关闭:,我在web上没有找到任何其他信息来支持这一声明,但是我使用套接字实现了HTTP请求,并且我注意到了显著的加速(4到6倍)

所以我的问题是:有人确切地知道HttpWebRequest对象是如何工作的吗?除了上面提到的以外,还有其他解决方法吗?或者有没有用C#anywhere编写的高速网络爬虫的例子?

您应该使用不阻塞且异步的方法


在处理与I/O绑定的异步时,仅仅因为生成了一个线程来执行I/O工作,该线程仍将被阻塞,等待硬件(在本例中是网卡)响应。如果使用内置的BeginGetResponse,那么该线程将在网卡上排队,然后可以执行更多工作。硬件完成后,它会通知您将在何时调用回调。

您是否尝试过使用诸如BeginGetResponse()之类的异步方法

如果您使用的是.net 4.0,您可能需要尝试此代码。基本上,我使用任务在特定站点上发出1000个请求(我使用任务在我的开发机器上对应用程序进行负载测试,我看不到这样的限制,因为我的应用程序正在快速连续地看到这些请求)

公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
对于(int i=0;i<1000;i++)
{
var webRequest=webRequest.Create(textBox1.Text);
webRequest.GetReponseAsync().ContinueWith(t=>
{
if(t.Exception==null)
{
使用(var sr=newstreamreader(t.Result.GetResponseStream())
{
字符串str=sr.ReadToEnd();
}
}
其他的
System.Diagnostics.Debug.WriteLine(t.Exception.InnerException.Message);
});
}
}
}
公共静态类WebRequestExtensions
{
公共静态任务GetResponseAsync(此WebRequest请求)
{
返回Task.Factory.fromsync(request.BeginGetResponse,request.EndGetResponse,null);
}
}
由于这里的工作负载是受I/O限制的,因此不需要生成线程来完成作业,实际上可能会影响性能。在WebClient类上使用异步方法会使用I/O完成端口,因此性能更高,资源消耗更少。

我想指出,该方法并非完全异步:(来自)

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


您可以配置每个域的连接限制,但默认情况下,连接限制是全局的。
  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);
    }
  }