我正在尝试创建一个类,以便在不同的线程上同时发送多个http请求,以尝试加快通过互联网获取多个文档。
我实现了这个,但是当我从1增加到2个线程时,执行时间加倍,从1到4个线程,执行时间翻两番。我认为它应该在超过1个线程上更快!
这是代码,也许我有一些奇怪的问题。
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;
}
}
}
更新: 我添加了这个,但它没有帮助
ServicePointManager.DefaultConnectionLimit = numThreads;
我想也许我连接到的网络路径(大学)限制为每台PC或某物的一个出站连接,并因请求多个而惩罚我...... idk ......
答案 0 :(得分:1)
这里可能会发生一些事情,第一件事是您达到了网络请求允许的连接数限制。默认情况下,它设置为2,因此要更改它,在函数的开头,您可以将其更新为您正在使用的线程数。
ServicePointManager.DefaultConnectionLimit = 10;
// 10 should match the number of threads you're executing
除此之外,它取决于您监控执行时间的位置。如果你正在监视整个执行时间,你应该注意你正在做的各种事情,比如实现你没有使用的队列。
答案 1 :(得分:0)
使用新的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);
}
}
}
}
使用以下代码对cnn.com运行10次迭代(如上所述):
[Test]
public void YieldResponse()
{
IEnumerable<Task<HttpResponseMessage>> responses = new ThreadedHttpGetter().GetResponses(Enumerable.Repeat(uri, iterations));
Console.WriteLine(responses.Count());
}
导致控制台输出:
10 测试跑了280ms
显然,这将取决于您的网络连接的容量和提供响应的网站。
更新
我偶然发现了Stephen Toub的这篇博客文章。这真的是你想要的,他甚至在他的评论中给出了一个具体的例子,详细描述了你的目标!
http://blogs.msdn.com/b/pfxteam/archive/2012/03/04/10277325.aspx