首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >DynamicObject和TrySetMember性能与ExpandoObject性能的对比

DynamicObject和TrySetMember性能与ExpandoObject性能的对比
EN

Stack Overflow用户
提问于 2012-03-03 06:48:47
回答 1查看 5.3K关注 0票数 5

我正在使用一个自定义的DynamicObject实现,它非常适合我的应用程序,只是我遇到了一些性能问题。对于dynamics来说,预计会有一些性能开销,但我看到即使使用ExpandoObject,也会出现明显的(读:数量级)性能损失。

我不能使用ExpandoObject的原因是我想覆盖它的一些行为。我已经把这个问题归结为下面一个非常简单的例子。

我的自定义ExpandoObject代码如下(简化为足以显示问题的代码) --

代码语言:javascript
运行
复制
public class SuperExpando : DynamicObject
{
    public Dictionary<string, object> dictionary = new Dictionary<string, object>();
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;
        return true;
    }
}

public dynamic m = new SuperExpando();

当我直接在动态对象的字典中设置值时(例如,m.dictionary"keyname“= 500),我看到与ExpandoObject类似的性能,这是在字典中设置键的值的毫秒以下的时间。当我使用TrySetMember覆盖(即m.keyname = 500)时,我看到每个键值集的性能下降到30ms - 50ms。当写入大量密钥时,这显然会成为一个问题。即使我一次又一次地写入相同的密钥,通过TrySetMember访问它也需要相同的时间。

我真正的性能问题似乎与我使用动态的事实无关,因为它使用了TrySetMember覆盖。为了好玩我甚至注释掉了

代码语言:javascript
运行
复制
dictionary[binder.Name] = value;

在TrySetMember方法中,只留下了一个"return true;",性能也是一样的。

如果我将如下内容添加到我的SuperExpando类中--

代码语言:javascript
运行
复制
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
    if (dictionary.ContainsKey(binder.Name))
    {
        result = dictionary[binder.Name];
        return true;
    }
    return false; 
}

通过TryGetMember访问(读取)变量的性能问题是相同的,而直接读取字典可以提供合理的性能。

有什么想法吗?

-BJ Quinn

编辑:这里是完整的示例代码。只需创建一个窗体,并在其上放置一个运行go_Click事件的按钮,然后将您的项目设置为控制台应用程序。对我来说,在ExpandoObject中设置所有50个关键点需要大约30ms,而SuperExpando至少需要大约750ms。

代码语言:javascript
运行
复制
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Dynamic;

namespace test
{
    public partial class ExpandoTest : Form
    {
        public ExpandoTest()
        {
            InitializeComponent();
        }

        public class SuperExpando : DynamicObject
        {
            public Dictionary<string, object> dictionary = new Dictionary<string, object>();

            public override bool TrySetMember(SetMemberBinder binder, object value)
            {
                //dictionary[binder.Name] = value;
                return true;
            }
        }

        DateTime lasttime = DateTime.Now;

        public void outputtime(string label = "")
        {
            TimeSpan elapsedtime = DateTime.Now - lasttime;
            Double elapsedms = elapsedtime.TotalMilliseconds;
            Console.WriteLine(label + " : " + elapsedms.ToString());
            lasttime = DateTime.Now;
        }

        private void go_Click(object sender, EventArgs e)
        {
            outputtime("Time spent waiting on user");
            dynamic se = new SuperExpando();
            outputtime("Declared SuperExpando");
            se.test120 = 5;
            se.test121 = 5;
            se.test122 = 5;
            se.test123 = 5;
            se.test124 = 5;
            se.test125 = 5;
            se.test126 = 5;
            se.test127 = 5;
            se.test128 = 5;
            se.test129 = 5;
            se.test130 = 5;
            se.test131 = 5;
            se.test132 = 5;
            se.test133 = 5;
            se.test134 = 5;
            se.test135 = 5;
            se.test136 = 5;
            se.test137 = 5;
            se.test138 = 5;
            se.test139 = 5;
            se.test140 = 5;
            se.test141 = 5;
            se.test142 = 5;
            se.test143 = 5;
            se.test144 = 5;
            se.test145 = 5;
            se.test146 = 5;
            se.test147 = 5;
            se.test148 = 5;
            se.test149 = 5;
            se.test150 = 5;
            se.test151 = 5;
            se.test152 = 5;
            se.test153 = 5;
            se.test154 = 5;
            se.test155 = 5;
            se.test156 = 5;
            se.test157 = 5;
            se.test158 = 5;
            se.test159 = 5;
            se.test160 = 5;
            se.test161 = 5;
            se.test162 = 5;
            se.test163 = 5;
            se.test164 = 5;
            se.test165 = 5;
            se.test166 = 5;
            se.test167 = 5;
            se.test168 = 5;
            se.test169 = 5;
            outputtime("Time to Run SuperExpando, set 50 test key/value pairs -- (not even setting values, just returning true from TrySetMember!)");

            dynamic eo = new ExpandoObject();
            outputtime("Declared ExpandoObject");
            eo.test120 = 5;
            eo.test121 = 5;
            eo.test122 = 5;
            eo.test123 = 5;
            eo.test124 = 5;
            eo.test125 = 5;
            eo.test126 = 5;
            eo.test127 = 5;
            eo.test128 = 5;
            eo.test129 = 5;
            eo.test130 = 5;
            eo.test131 = 5;
            eo.test132 = 5;
            eo.test133 = 5;
            eo.test134 = 5;
            eo.test135 = 5;
            eo.test136 = 5;
            eo.test137 = 5;
            eo.test138 = 5;
            eo.test139 = 5;
            eo.test140 = 5;
            eo.test141 = 5;
            eo.test142 = 5;
            eo.test143 = 5;
            eo.test144 = 5;
            eo.test145 = 5;
            eo.test146 = 5;
            eo.test147 = 5;
            eo.test148 = 5;
            eo.test149 = 5;
            eo.test150 = 5;
            eo.test151 = 5;
            eo.test152 = 5;
            eo.test153 = 5;
            eo.test154 = 5;
            eo.test155 = 5;
            eo.test156 = 5;
            eo.test157 = 5;
            eo.test158 = 5;
            eo.test159 = 5;
            eo.test160 = 5;
            eo.test161 = 5;
            eo.test162 = 5;
            eo.test163 = 5;
            eo.test164 = 5;
            eo.test165 = 5;
            eo.test166 = 5;
            eo.test167 = 5;
            eo.test168 = 5;
            eo.test169 = 5;
            outputtime("Time to Run ExpandoObject, set 50 test key/value pairs");
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-03-04 08:33:46

首先,你不应该像这样测量时间。DateTime.Now的精度不能精确到毫秒。为此,您应该使用Stopwatch

其次,在一般的.Net中,尤其是在处理dynamic时,顺序很重要。这是因为CLR和DLR第一次必须计算一些东西,但第二次可以从缓存中检索。

第三,在我的测试中,我肯定没有看到750ms,或者接近750ms的任何东西。

如果我首先运行SuperExpando,并执行两次这两个测试,我会得到如下时间:

代码语言:javascript
运行
复制
SuperExpando: 50,7736 ms
EpandoObject: 27,786 ms
SuperExpando: 0,0285 ms
EpandoObject: 0,0373 ms

因此,SuperExpando速度较慢,差异可能很大,但这只是第一次。当您再次以相同的类型运行相同的代码时,速度会快得多。

当我们颠倒顺序时会发生什么?

代码语言:javascript
运行
复制
EpandoObject: 33,3107 ms
SuperExpando: 43,7383 ms
EpandoObject: 0,0348 ms
SuperExpando: 0,0186 ms

SuperExpando仍然较慢,但差别现在更小了。同样,这两种方法的第二次运行速度都快了几个数量级。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9541454

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档