c# - 动态对象的并行性能

标签 c# task-parallel-library dynamic-language-runtime

以下代码大约运行 2.5 秒:

static void Main(string[] args)
{
    var service = new Service();
    Parallel.For(0, 100, i => {
        dynamic user = new ExpandoObject();
        user.data = new ExpandoObject();
        user.data.id = i;
        user.data.name = "User Name";
        var parsed = service.Parse(user);
    });
}

public class Service
{
    public User Parse(dynamic dynamicUser)
    {
        if (dynamicUser.data != null)
        {
            return new User
            {
                Id = dynamicUser.data.id,
                Name = dynamicUser.data.name
            };
        }
        return null;
    }
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

但是,如果我将 Parallel.For() 循环更改为简单的 For 循环,它会在大约 200 毫秒内运行:

for (var i = 0; i < 100; i++)

所以我的问题是,为什么并行运行时会慢很多?

我的理论是,解析每个线程完成一次的动态对象会产生一些开销。在简单循环中,DLR 第一次执行它的操作,然后不需要为每个后续调用执行操作。

但同时,DLR 的开销发生在每次调用中。

这是一个正确的假设,还是我离题太远了?

最佳答案

我怀疑您被诊断误导了。特别是,如果运行一个循环 100 次需要 2.5 秒,那真的非常非常慢。这是在调试器下吗?

这是我的盒子上的结果,代码是用 /o+ 编译的,然后在控制台中运行。请注意,我在每个测试中运行 1,000,000 次循环迭代。

Void ExecuteParallel(): 00:00:00.7311773
Void ExecuteSerial(): 00:00:02.0514120
Void ExecuteParallel(): 00:00:00.6897816
Void ExecuteSerial(): 00:00:02.0389325
Void ExecuteParallel(): 00:00:00.6754025
Void ExecuteSerial(): 00:00:02.0653801
Void ExecuteParallel(): 00:00:00.7136330
Void ExecuteSerial(): 00:00:02.0477593
Void ExecuteParallel(): 00:00:00.6742260
Void ExecuteSerial(): 00:00:02.0476146

它并没有像您对四核 i7 的期望那样那么并行,但我怀疑这是由于 Servy 提到的上下文切换等 - 也可能是对执行缓存的争用在 DLR 中。不过,它比串联运行要快。

亲自尝试代码,看看您在机器上得到了什么 - 但不是在调试器下。

代码:

using System;
using System.Diagnostics;
using System.Dynamic;
using System.Threading.Tasks;

class Test
{
    const int Iterations = 1000000;

    static void Main(string[] args)
    {
        for (int i = 0; i < 5; i++)
        {
            RunTest(ExecuteParallel);
            RunTest(ExecuteSerial);
        }

    }

    static void RunTest(Action action)
    {
        var sw = Stopwatch.StartNew();
        action();
        sw.Stop();
        Console.WriteLine("{0}: {1}", action.Method, sw.Elapsed);
    }

    static void ExecuteParallel()
    {
        var service = new Service();
        Parallel.For(0, Iterations, i => {
            dynamic user = new ExpandoObject();
            user.data = new ExpandoObject();
            user.data.id = i;
            user.data.name = "User Name";
            var parsed = service.Parse(user);
        });
    }

    static void ExecuteSerial()
    {
        var service = new Service();
        for (int i = 0; i < Iterations; i++)
        {
            dynamic user = new ExpandoObject();
            user.data = new ExpandoObject();
            user.data.id = i;
            user.data.name = "User Name";
            var parsed = service.Parse(user);
        }
    }
}

public class Service
{
    public User Parse(dynamic dynamicUser)
    {
        if (dynamicUser.data != null)
        {
            return new User
            {
                Id = dynamicUser.data.id,
                Name = dynamicUser.data.name
            };
        }
        return null;
    }
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

关于c# - 动态对象的并行性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12981692/

相关文章:

c# - ASP.Net Video 中的 DataList 应在点击时放大

c# - 这是 Partitioner.Create(int fromInclusive, int toExclusive) 中的错误吗?

.net - 查询托管环境中接口(interface)的 IronPython 脚本

c# - 观察者设计模式的更新方法

c# - 如何在解析 xml (c#) 时进行操作(avg、cnt 等)?

c# - 将多线程访问的 ConcurrentBag 转储到文件的速度不够快

.net - Visual Studio 文档 XML 注释标签中神秘的 "usage"标签

c# - 使用动态关键字从 C# 运行 IronPython 对象

c# - 动态对象转换的语法替代方法

c# - XmlSerializer 不可靠还是我做错了什么?