【发布时间】:2015-02-06 14:18:44
【问题描述】:
我有一个应用程序,我需要一次发出很多 httpWebRequest 并尽可能快地获得每个应用程序的响应。 实际上,我不需要快速获得所有响应,我需要尽可能快地获得每个响应。我的意思是在我发送每个请求和得到响应之间必须有最短时间。
我阅读了很多关于 async/await 技术的文章并选择了这个解决方案:
private static void Main()
{
ServicePointManager.DefaultConnectionLimit = 100;
ServicePointManager.Expect100Continue = false;
ServicePointManager.UseNagleAlgorithm = false;
ProcessAsync("https://www.google.ru");
Console.ReadKey();
}
private static void ProcessAsync(string url)
{
for (var i = 1; i <= 100; i++)
Task.Factory.StartNew(async () => await ProcessInternalAsync(url));
}
private static async Task ProcessInternalAsync(string url)
{
var request = GetRequest(url);
var sw = Stopwatch.StartNew();
await GetStringContentAsync(request);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
public static async Task<string> GetStringContentAsync(HttpWebRequest webRequest)
{
using (var response = (HttpWebResponse) await webRequest.GetResponseAsync()
.ConfigureAwait(false))
{
var content = await GetStringContentFromResponseAsync(response)
.ConfigureAwait(false);
return content;
}
}
private static async Task<string> GetStringContentFromResponseAsync(HttpWebResponse response)
{
using (var responseStream = GetStreamForResponse(response))
{
if (responseStream == null)
return null;
using (var streamReader = new StreamReader(responseStream))
{
var content = await streamReader.ReadToEndAsync()
.ConfigureAwait(false);
return content;
}
}
}
这可行,但速度很慢..(每个请求 500-1600 毫秒)
所以我尝试了没有异步/等待的“简单”解决方案:
private static void Main()
{
ServicePointManager.DefaultConnectionLimit = 100;
ServicePointManager.Expect100Continue = false;
ServicePointManager.UseNagleAlgorithm = false;
Process("https://www.google.ru");
Console.ReadKey();
}
private static void Process(string url)
{
for (var i = 1; i <= 100; i++)
Task.Factory.StartNew(() => ProcessInternal(url));
}
private static void ProcessInternal(string url)
{
var request = GetRequest(url);
var sw = Stopwatch.StartNew();
GetStringContent(request);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
public static string GetStringContent(HttpWebRequest webRequest)
{
using (var response = (HttpWebResponse) webRequest.GetResponse())
{
var content = GetStringContentFromResponse(response);
return content;
}
}
private static string GetStringContentFromResponse(HttpWebResponse response)
{
using (var responseStream = GetStreamForResponse(response))
{
if (responseStream == null)
return null;
using (var streamReader = new StreamReader(responseStream))
{
var content = streamReader.ReadToEnd();
return content;
}
}
}
而且它的运行速度要快得多! (每个请求 55-180 毫秒)。
这里有一些其他的方法:
private static HttpWebRequest GetRequest(string url)
{
var request = (HttpWebRequest) WebRequest.Create(url);
request.Timeout = 15000;
request.Proxy = null;
request.Headers.Add("Accept-Encoding", "gzip,deflate");
return request;
}
private static Stream GetStreamForResponse(HttpWebResponse webResponse)
{
var responseStream = webResponse.GetResponseStream();
if (responseStream == null)
return null;
Stream stream;
switch (webResponse.ContentEncoding.ToUpperInvariant())
{
case "GZIP":
stream = new GZipStream(responseStream, CompressionMode.Decompress);
break;
case "DEFLATE":
stream = new DeflateStream(responseStream, CompressionMode.Decompress);
break;
default:
stream = responseStream;
break;
}
return stream;
}
所以我的问题是:为什么差别这么大?我认为当我将 await 与 I/O 操作一起使用时 - 这是一种好方法,也是执行 HTTP 请求的最佳方法。但在实践中并不完全正确。
在没有 async/await 的解决方案中,我们在等待响应时有线程阻塞,如果它不是 Google 并且将是具有长时间运行操作的服务器,则此请求将阻塞我的所有应用程序。
可能有更好的方法来解决我的问题?
附:
这个“魔法”:
ServicePointManager.Expect100Continue = false;
ServicePointManager.UseNagleAlgorithm = false;
只是来自互联网的一些建议,我不知道它是如何工作的..
更新 感谢Servy,我终于明白了我在测量方面的错误。现在 Process 方法如下所示:
private static void Process(string url)
{
var taskCollection = new List<Task>();
for (var i = 1; i <= 100; i++)
{
var sw = Stopwatch.StartNew();
taskCollection.Add(Task.Factory.StartNew(() =>
{
ProcessInternal(url);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}));
}
Task.WaitAll(taskCollection.ToArray());
}
现在第二个解决方案显示其毫秒数(请求为 300-1000 毫秒)。但无论如何,它比 async/await 更快。 async/await 方法一定要慢吗?
【问题讨论】:
标签: c# multithreading asynchronous httpwebrequest httpwebresponse