我正在尝试同时执行2000个http查询。
使用此代码(主要由响应服务器组成)进行的测试大约需要15秒:
public void testTasks()
{
var urls = new List<string>();
urls.AddRange(createUrls());
var start = DateTime.Now;
ConcurrentQueue<string> contents = new ConcurrentQueue<string>();
Task.WaitAll(urls.Select(url =>
{
var client = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
return client.GetAsync(url).ContinueWith(response =>
{
try
{
var content = response.Result.Content.ReadAsStringAsync().Result;
contents.Enqueue(content);
}
catch (Exception e)
{
}
});
}).ToArray());
var end = DateTime.Now;
var time = end - start;
Console.WriteLine("Time spent in Tasks : " + time.TotalSeconds);
Console.WriteLine("Queue size : " + contents.Count);
}
现在,我使用Parallel.foreach进行相同的测试,并获得1分钟18秒的运行时间:
public void testParallelForeach()
{
var urls = new List<string>();
urls.AddRange(createUrls());
var start = DateTime.Now;
ConcurrentQueue<string> contents = new ConcurrentQueue<string>();
Parallel.ForEach(urls, new ParallelOptions() { MaxDegreeOfParallelism = urls.Count }, url =>
{
var client = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
try
{
string content = client.GetStringAsync(url).Result;
contents.Enqueue(content);
}
catch (Exception e)
{
}
});
var end = DateTime.Now;
var time = end - start;
Console.WriteLine("Time spent in ParallelForeach : " + time.TotalSeconds);
Console.WriteLine("Queue size : " + contents.Count);
}
如您所见,我使用的MaxDegreeOfParallelism等于服务器数量。但这似乎还不够。
编辑
所以我的问题是:
-为什么我的表现有如此大的差异?
-我们可以使用parallel.foreach获得相同的性能吗?
参考方案
-为什么我的表现有如此大的差异?
因为将Parallel.ForEach
用于IO绑定工作没有意义。 Parallel.ForEach
仅用于CPU绑定工作。同样,Parallel.ForEach
具有“加速”效果,它不是从MaxDegreeOfParallelism
开始,它从1个线程开始,然后不断添加线程,因为它检测到工作可能使用更多线程,直到达到MaxDegreeOfParallelism
(这是有原因的)称为“ MaxDegreeOfParallelism”,而不是“ DegreeOfParallelism”)。使用IO绑定工作而不是CPU绑定工作会极大地破坏该调度算法。
-我们可以使用parallel.foreach获得相同的性能吗?
不可以,因为您使用的工具不正确,否则错误的方法总会胜过更正确的方法(您的第一种方法是)
但是,使用Async
方法然后立即调用.Result
仍然是错误的方法,最好的方法是使用适当的异步/等待(也可以使用Stopwatch
而不是DateTime
来确保经过的时间并处理掉您创建的一次性课程)
public async Task TestTasksProperly()
{
var urls = new List<string>();
urls.AddRange(createUrls());
var stopwatch = Stopwatch.StartNew();
ConcurrentQueue<string> contents = new ConcurrentQueue<string>();
await Task.WhenAll(urls.Select(url => QueryUrl(url, contents)))).ConfigureAwait(false);
var time = stopwatch.ElapsedMilliseconds / 1000.0;
Console.WriteLine("Time spent in Tasks : " + time);
Console.WriteLine("Queue size : " + contents.Count);
}
private static async Task QueryUrl(string url, ConcurrentQueue<string> contents)
{
using (var client = new HttpClient {Timeout = TimeSpan.FromSeconds(10)})
{
using (var response = await client.GetAsync(url).ConfigureAwait(false))
{
try
{
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
contents.Enqueue(content);
}
catch (Exception e)
{
}
}
}
}
剃刀付款集成->如何通过关闭按钮X检测剃刀付款模型是否关闭 - javascript当用户关闭而无需付款时,我在CI框架中使用Razorpay,请创建razor支付模型,然后取消订单,我希望按状态更改为已取消的状态触发查询。所以我怎么能检测到这一点。我已经通过单击jQuery单击关闭功能但无法使用... javascript大神给出的解决方案 Razorpay提供了JS方法来检测模式关闭。您编写的任何JS代码都不会在结帐页面上运行,因为它是…
如何使用箭头符号(->)创建受保护的方法? - java当我们编写以下代码时Stream.of(1,2,3,4,5).filter(i -> (i%2 == 0)).map( i -> i*i ); 表达式i -> (i%2 == 0)或i -> i*i将变为私有方法。在我的用例中,编写了一个junit测试,以确保没有方法是私有的(是的,这是强制性的),并且对于这些lambda表达式而言,…
无法从ArrayList <String>转换为List <Comparable> - java当我写下面的代码时,编译器说 无法从ArrayList<String>转换为List<Comparable>private List<Comparable> get(){ return new ArrayList<String>(); } 但是当我用通配符编写返回类型时,代码会编译。private List&l…
粗糙的Unicode->没有CLDR的语言代码? - javascript我在写字典应用。如果用户键入Unicode字符,我想检查该字符是哪种语言。例如字 - returns ['zh', 'ja', 'ko'] العربية - returns ['ar'] a - returns ['en', 'fr', …
将谓词<T>转换为Func <T,bool> - c#我有一个包含成员Predicate的类,希望在Linq表达式中使用该类:using System.Linq; class MyClass { public bool DoAllHaveSomeProperty() { return m_instrumentList.All(m_filterExpression); } private IEnumerable&…