C#:AsParallel - 顺序重要吗?

发布于 2024-10-18 04:18:18 字数 470 浏览 3 评论 0原文

我正在构建一个简单的 LinQ 到对象查询,我想对其进行并行化,但是我想知道语句的顺序是否重要?

例如

IList<RepeaterItem> items;

var result = items
        .Select(item => item.FindControl("somecontrol"))
        .Where(ctrl => SomeCheck(ctrl))
        .AsParallel();

vs.

var result = items
        .AsParallel()
        .Select(item => item.FindControl("somecontrol"))
        .Where(ctrl => SomeCheck(ctrl));

有什么区别吗?

I'm building a simple LinQ-to-object query which I'd like to parallelize, however I'm wondering if the order of statements matter ?

e.g.

IList<RepeaterItem> items;

var result = items
        .Select(item => item.FindControl("somecontrol"))
        .Where(ctrl => SomeCheck(ctrl))
        .AsParallel();

vs.

var result = items
        .AsParallel()
        .Select(item => item.FindControl("somecontrol"))
        .Where(ctrl => SomeCheck(ctrl));

Would there be any difference ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半﹌身腐败 2024-10-25 04:18:18

绝对地。在第一种情况下,投影和过滤将串行完成,只有然后才会并行化。

在第二种情况下,投影和过滤将并行发生。

除非您有特殊原因使用第一个版本(例如,投影具有线程关联性,或其他一些奇怪的情况),否则您应该使用第二个版本。

编辑:这是一些测试代码。虽然许多基准测试都存在缺陷,但结果相当具有结论性:

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;

class Test
{
    static void Main()
    {
        var query = Enumerable.Range(0, 1000)
                              .Select(SlowProjection)
                              .Where(x => x > 10)
                              .AsParallel();
        Stopwatch sw = Stopwatch.StartNew();
        int count = query.Count();
        sw.Stop();
        Console.WriteLine("Count: {0} in {1}ms", count,
                          sw.ElapsedMilliseconds);

        query = Enumerable.Range(0, 1000)
                          .AsParallel()
                          .Select(SlowProjection)
                          .Where(x => x > 10);
        sw = Stopwatch.StartNew();
        count = query.Count();
        sw.Stop();
        Console.WriteLine("Count: {0} in {1}ms", count,
                          sw.ElapsedMilliseconds);
    }

    static int SlowProjection(int input)
    {
        Thread.Sleep(100);
        return input;
    }
}

结果:

Count: 989 in 100183ms
Count: 989 in 13626ms

现在 PFX 中出现了很多启发式的东西,但很明显第一个结果根本没有被并行化,而第二个有。

Absolutely. In the first case, the projection and filtering will be done in series, and only then will anything be parallelized.

In the second case, both the projection and filtering will happen in parallel.

Unless you have a particular reason to use the first version (e.g. the projection has thread affinity, or some other oddness) you should use the second.

EDIT: Here's some test code. Flawed as many benchmarks are, but the results are reasonably conclusive:

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;

class Test
{
    static void Main()
    {
        var query = Enumerable.Range(0, 1000)
                              .Select(SlowProjection)
                              .Where(x => x > 10)
                              .AsParallel();
        Stopwatch sw = Stopwatch.StartNew();
        int count = query.Count();
        sw.Stop();
        Console.WriteLine("Count: {0} in {1}ms", count,
                          sw.ElapsedMilliseconds);

        query = Enumerable.Range(0, 1000)
                          .AsParallel()
                          .Select(SlowProjection)
                          .Where(x => x > 10);
        sw = Stopwatch.StartNew();
        count = query.Count();
        sw.Stop();
        Console.WriteLine("Count: {0} in {1}ms", count,
                          sw.ElapsedMilliseconds);
    }

    static int SlowProjection(int input)
    {
        Thread.Sleep(100);
        return input;
    }
}

Results:

Count: 989 in 100183ms
Count: 989 in 13626ms

Now there's a lot of heuristic stuff going on in PFX, but it's pretty obvious that the first result hasn't been parallelized at all, whereas the second has.

寂寞花火° 2024-10-25 04:18:18

这确实很重要,而不仅仅是性能方面。
第一个和第二个查询的结果不相等。
有一种解决方案可以并行处理并保持原始顺序。
使用AsParallel().AsOrdered()。第三个查询显示了它。

var SlowProjection = new Func<int, int>((input) => { Thread.Sleep(100); return input; });

var Measure = new Action<string, Func<List<int>>>((title, measure) =>
{
    Stopwatch sw = Stopwatch.StartNew();
    var result = measure();
    sw.Stop();
    Console.Write("{0} Time: {1}, Result: ", title, sw.ElapsedMilliseconds);
    foreach (var entry in result) Console.Write(entry + " ");         
});

Measure("Sequential", () => Enumerable.Range(0, 30)
    .Select(SlowProjection).Where(x => x > 10).ToList());
Measure("Parallel", () => Enumerable.Range(0, 30).AsParallel()
    .Select(SlowProjection).Where(x => x > 10).ToList());
Measure("Ordered", () => Enumerable.Range(0, 30).AsParallel().AsOrdered()
    .Select(SlowProjection).Where(x => x > 10).ToList());

结果:

Sequential Time: 6699, Result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Parallel Time: 1462, Result: 12 16 22 25 29 14 17 21 24 11 15 18 23 26 13 19 20 27 28
Ordered Time: 1357, Result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

我对此感到惊讶,但经过 10 次以上的测试运行后,结果是一致的。我调查了一下,结果发现这是 .Net 4.0 中的一个“bug”。在 4.5 中,AsParallel() 并不慢于 AsParallel().AsOrdered()

参考位于:

http://msdn.microsoft.com/en-us/library/dd460677(v=vs.110).aspx

It does matter and not just in performance.
The result of the first and the second queries are not equal.
There is solution to have parallel processing and keeping the original order.
Use AsParallel().AsOrdered(). Third query shows it.

var SlowProjection = new Func<int, int>((input) => { Thread.Sleep(100); return input; });

var Measure = new Action<string, Func<List<int>>>((title, measure) =>
{
    Stopwatch sw = Stopwatch.StartNew();
    var result = measure();
    sw.Stop();
    Console.Write("{0} Time: {1}, Result: ", title, sw.ElapsedMilliseconds);
    foreach (var entry in result) Console.Write(entry + " ");         
});

Measure("Sequential", () => Enumerable.Range(0, 30)
    .Select(SlowProjection).Where(x => x > 10).ToList());
Measure("Parallel", () => Enumerable.Range(0, 30).AsParallel()
    .Select(SlowProjection).Where(x => x > 10).ToList());
Measure("Ordered", () => Enumerable.Range(0, 30).AsParallel().AsOrdered()
    .Select(SlowProjection).Where(x => x > 10).ToList());

Result:

Sequential Time: 6699, Result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Parallel Time: 1462, Result: 12 16 22 25 29 14 17 21 24 11 15 18 23 26 13 19 20 27 28
Ordered Time: 1357, Result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

I was surprised about that, but the result was consistent after 10+ test run. I investigated a bit and it turned out to be a "bug" in .Net 4.0. In 4.5 AsParallel() is not slower than AsParallel().AsOrdered()

Reference is here:

http://msdn.microsoft.com/en-us/library/dd460677(v=vs.110).aspx

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文