使用Parallel.foreach时无法为HTTP查询获得正确的并行度 - c#

我正在尝试同时执行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&…