C# 多线程httprequests
我试图创建一个类,在不同的线程上同时发送多个http请求,以加快通过internet获取多个文档的速度 我实现了这一点,但当我从1个线程增加到2个线程时,执行时间会翻倍,从1个线程增加到4个线程,执行时间会翻倍。我认为它应该比1个线程更快 这是代码,也许我有一些问题C# 多线程httprequests,c#,multithreading,C#,Multithreading,我试图创建一个类,在不同的线程上同时发送多个http请求,以加快通过internet获取多个文档的速度 我实现了这一点,但当我从1个线程增加到2个线程时,执行时间会翻倍,从1个线程增加到4个线程,执行时间会翻倍。我认为它应该比1个线程更快 这是代码,也许我有一些问题 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
namespace scomA3proj
{
public class MultithreadedHttpRequests_James : IMultithreadedHttpRequests_James
{
List<string> Urls;
string[] responses;
public List<string> getHttpResponses(List<string> urls, int numThreads)
{
this.Urls = urls;
responses = new string[urls.Count];
List<Thread> threads = new List<Thread>();
for (int i = 0; i < numThreads; i++)
{
Thread bgw = new Thread(new ParameterizedThreadStart(bgw_DoWork));
bgw.Start();
threads.Add(bgw);
}
for (int i = 0; i < numThreads; i++)
{
threads[i].Join();
}
return responses.ToList();
}
void bgw_DoWork(object sender)
{
while (true)
{
int index = getNext();
if (index == -1) break;
string s = Urls[index];
responses[index] = HttpRequestWrapper.getResponse(s);
}
}
int counter = 0;
int getNext()
{
int res = 0;
lock (this)
{
res = counter;
counter++;
}
if (res >= Urls.Count)
return -1;
return res;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
namespace scomA3proj
{
public sealed class HttpRequestWrapper
{
/// <summary>
/// Gets the HTTP response from a web page. Headers are used based on the useHeaders flag.
/// </summary>
/// <param name="url">URI formatted URL(example:"http://www.yahoo.com").</param>
/// <returns>Returns Html source of requested page.</returns>
public static string getResponse(string url)
{
string result = "";
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
result = reader.ReadToEnd();
}
catch (Exception ex)
{
result = "error";
}
return result;
}
}
}
我想可能我连接到的网络路径(大学)限制为每台电脑一个出站连接或其他什么,并惩罚我请求多个…idk…这里可能会发生一些事情,首先是你达到了web请求允许的连接数限制。默认情况下,该值设置为2,因此要更改该值,可以在函数开始时将其更新为正在使用的线程数
ServicePointManager.DefaultConnectionLimit = 10;
// 10 should match the number of threads you're executing
除此之外,这取决于您在哪里监视执行时间。如果您正在监视总体执行时间,则应注意您正在执行的其他工作,例如实现一个不使用的队列。使用新的System.Net.Http.HttpClient,您可以轻松完成此操作,而无需滚动自己的代码:
public class ThreadedHttpGetter
{
public IEnumerable<Task<HttpResponseMessage>> GetResponses(IEnumerable<string> uris)
{
foreach (string uri in uris)
{
using (var httpClient = new HttpClient())
{
yield return httpClient.GetAsync(uri);
}
}
}
}
公共类ThreadedHttpGetter
{
公共IEnumerable GetResponses(IEnumerable URI)
{
foreach(uri中的字符串uri)
{
使用(var httpClient=new httpClient())
{
返回httpClient.GetAsync(uri);
}
}
}
}
使用以下代码对cnn.com运行10次迭代(如上所述):
[Test]
public void YieldResponse()
{
IEnumerable<Task<HttpResponseMessage>> responses = new ThreadedHttpGetter().GetResponses(Enumerable.Repeat(uri, iterations));
Console.WriteLine(responses.Count());
}
[测试]
公众回应(
{
IEnumerable responses=new ThreadedHttpGetter().GetResponses(Enumerable.Repeat(uri,迭代));
Console.WriteLine(responses.Count());
}
导致控制台输出为:
十,
测试时间为280毫秒
显然,这将取决于网络连接的容量和提供响应的站点
更新:
我刚刚偶然发现了Stephen Toub的这篇博文。这真的是你想要的,他甚至在评论中给出了一个具体的例子,特别详细说明了你想要什么
是的……不要问……我尝试了一些东西,但忘记了删除它。我不知道这是否相关,但我尝试使用PowerShell作业执行类似的操作,而不是直接在.NET中创建线程。我遇到了与您类似的性能问题。我很想看看这个问题还带来了什么其他的想法。您在哪里捕获请求时间的开始和结束?或者,您只是捕获了总体执行时间吗?我找不到其他任何东西。是时候进行printf调试了:在代码中调用Debug.WriteLine和print操作和时间。我按原样运行了您的代码,它的伸缩性非常好。1个线程在58秒内执行227个请求,15个线程在10秒内执行。你想找哪一页?可能是你的本地网站减慢了速度?在www.cnn.com上试一试——它很重——我在单元测试中确实试过了。这毫无帮助。我正在40个文档上尝试这个。我不认为队列会影响执行时间,因为使用1个线程需要7秒来完成=p…我从那时起就删除了它。当你说执行时间加倍时,我们谈论的是什么程度的时间?如果您只做了一个请求,那么请求是否相当快?这是毫秒还是秒的问题?单线程…~7秒处理40个请求…2线程~14秒处理40个请求..4线程~28秒处理40个请求等等…James,你应该在自己的服务器实例上尝试你的应用程序;根据之前的一些聊天,您似乎正在其他网站上使用它,这些网站可能会对您的请求使用任何形式的速率限制。
[Test]
public void YieldResponse()
{
IEnumerable<Task<HttpResponseMessage>> responses = new ThreadedHttpGetter().GetResponses(Enumerable.Repeat(uri, iterations));
Console.WriteLine(responses.Count());
}