いくつかのパフォーマンスの問題が発生しているという事実を除けば、アプリケーションで完全に機能する DynamicObject のカスタム実装を使用しています。ダイナミクスではある程度のパフォーマンス オーバーヘッドが予想されますが、ExpandoObject を使用した場合でも、大幅な (桁違いの) パフォーマンスの低下が見られます。
ExpandoObject を使用できない理由は、その動作の一部をオーバーライドしたいからです。以下の非常に単純な例に問題を要約しました。
私のカスタム ExpandoObject コードは次のとおりです (問題を示すのに十分なコードに簡略化されています) --
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();
DynamicObject のディクショナリに値を直接設定すると (iemdictionary["keyname"] = 500)、ExpandoObject と同様のパフォーマンスが得られます。これは、ディクショナリにキーの値を設定するのにミリ秒未満の時間です。TrySetMember オーバーライド (iemkeyname = 500) を使用すると、キー値セットごとにパフォーマンスが 30 ミリ秒から 50 ミリ秒に低下します。多くのキーに書き込む場合、これは明らかに問題になります。同じキーに何度も書き込んでも、TrySetMember を介してアクセスすると同じ時間がかかります。
私の実際のパフォーマンスの問題は、TrySetMember オーバーライドと同様にダイナミクスを使用しているという事実とは関係がないようです。キックのために、私もコメントアウトしました
dictionary[binder.Name] = value;
TrySetMember メソッドで "return true;" だけを残し、パフォーマンスは同じでした。
次のようなものを SuperExpando クラスに追加すると --
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (dictionary.ContainsKey(binder.Name))
{
result = dictionary[binder.Name];
return true;
}
return false;
}
TryGetMember を介して変数にアクセスする (読み取る) パフォーマンスの問題は同じですが、ディクショナリを直接読み取ると妥当なパフォーマンスが得られます。
何か案は?
-BJクイン
編集: ここに完全なサンプル コードがあります。フォームを作成し、go_Click イベントを実行するボタンを配置し、プロジェクトをコンソール アプリケーションに設定するだけです。私の場合、ExpandoObject で 50 個のキーすべてを設定するのに約 30 ミリ秒かかりますが、SuperExpando では最小で約 750 ミリ秒かかります。
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");
}
}
}