动态创建类型的性能

发布于 2024-08-15 09:02:25 字数 4437 浏览 6 评论 0原文

使用 C#,我注意到使用动态生成类型的实例与简单结构填充列表时性能存在显着差异。下面的代码包含 4 种不同的方法来填充包含 100,000 个对象的列表。

每种方法的执行方式不同:

Button1:15 毫秒

Button2:31 毫秒

Button3 和 Button2: 31 毫秒4:300毫秒

注意,按钮3和4的代码4 来自 此主题

谁能解释为什么动态创建的对象速度较慢?

    public struct DataRow
    {
        public double t;
        public double vf;
        public double im;

        public double T { get { return t; } set { t = value; } }
        public double Vf { get { return vf; } set { vf = value; } }
        public double Im { get { return im; } set { im = value; } }
    }

    //Use struct defined above
    private void button1_Click(object sender, EventArgs e)
    {
        int n = 0;

        //adding rows
        List<DataRow> myTable = new List<DataRow>();
        DataRow myRow = new DataRow();

        start = DateTime.Now;

        while (n < 100000)
        {
            myRow.T = n * 1.0;
            myRow.Vf = 2.0;
            myRow.Im = 4.0;

            myTable.Add(myRow);

            n++;
        }
        end = DateTime.Now;
        System.TimeSpan diff = end.Subtract(start);
        label2.Text = diff.Seconds.ToString();
        label4.Text = diff.Milliseconds.ToString();

        dataGridView1.DataSource = myTable;
    }

    //define the list as it is done on buttons 3 & 4 but use the static struct
    private void button2_Click(object sender, EventArgs e)
    {
        Type myType = typeof(DataRow);

        Type listType = typeof(List<>);

        Type myListType = listType.MakeGenericType(myType);

        IList myTable = (IList)Activator.CreateInstance(myListType);

        DataRow bRow = new DataRow();

        int n = 0;
        start = DateTime.Now;
        while (n < 100000)
        {
            bRow.t = n * 1.0;
            bRow.vf = 2.0;
            bRow.im = 4.0;
            myTable.Add(bRow);

            n++;
        }
        end = DateTime.Now;
        System.TimeSpan diff = end.Subtract(start);
        label2.Text = diff.Seconds.ToString();
        label4.Text = diff.Milliseconds.ToString();
        dataGridView1.DataSource = myTable;

    }

    //Create assy at runtime and load dll
    private void button3_Click(object sender, EventArgs e)
    {
        Type myType = CreateDynRow();
        Assembly myAssy = Assembly.LoadFrom("DynaRowAssy.dll");
        Type myRow = myAssy.GetType("DynaRow");

        Type listType = typeof(List<>);

        Type myListType = listType.MakeGenericType(myRow);

        IList myTable = (IList)Activator.CreateInstance(myListType);

        FieldInfo piT = myRow.GetField("t");
        FieldInfo piVf = myRow.GetField("vf");
        FieldInfo piIm = myRow.GetField("im");

        ValueType aRow = (ValueType)Activator.CreateInstance(myRow);

        int n = 0;
        start = DateTime.Now;
        while (n < 100000)
        {
            piT.SetValue(aRow, 1 * n);
            piVf.SetValue(aRow, 2.0);
            piIm.SetValue(aRow, 4.0);
            myTable.Add(aRow);

            n++;
        }
        end = DateTime.Now;
        System.TimeSpan diff = end.Subtract(start);
        label2.Text = diff.Seconds.ToString();
        label4.Text = diff.Milliseconds.ToString();
        dataGridView1.DataSource = myTable;
    }

    //create assy at runtime in memory
    private void button4_Click(object sender, EventArgs e)
    {
        //build the assembly
        Type myType = CreateDynRow();

        Type listType = typeof(List<>);

        Type myListType = listType.MakeGenericType(myType);

        IList myTable = (IList)Activator.CreateInstance(myListType);

        FieldInfo piT = myType.GetField("t");
        FieldInfo piVf = myType.GetField("vf");
        FieldInfo piIm = myType.GetField("im");

        ValueType aRow = (ValueType)Activator.CreateInstance(myType);

        int n = 0;
        start = DateTime.Now;
        while (n < 100000)
        {
            piT.SetValue(aRow, 1 * n);
            piVf.SetValue(aRow, 2.0);
            piIm.SetValue(aRow, 4.0);
            myTable.Add(aRow);

            n++;
        }
        end = DateTime.Now;
        System.TimeSpan diff = end.Subtract(start);
        label2.Text = diff.Seconds.ToString();
        label4.Text = diff.Milliseconds.ToString();
        dataGridView1.DataSource = myTable;
    }

Using C#, I am noticing a significant difference in perfomance when populating a list with instances of a dynamically generated type versus a simple struct. The code below includes 4 different methods for populating a list with 100,000 objects.

Each method performs differently:

Button1: 15 milliseconds

Button2: 31 milliseconds

Button3 & 4: 300 milliseconds

Note, the code for button 3 & 4 came from this topic

Could anyone explain why the dynamically created object is slower?

    public struct DataRow
    {
        public double t;
        public double vf;
        public double im;

        public double T { get { return t; } set { t = value; } }
        public double Vf { get { return vf; } set { vf = value; } }
        public double Im { get { return im; } set { im = value; } }
    }

    //Use struct defined above
    private void button1_Click(object sender, EventArgs e)
    {
        int n = 0;

        //adding rows
        List<DataRow> myTable = new List<DataRow>();
        DataRow myRow = new DataRow();

        start = DateTime.Now;

        while (n < 100000)
        {
            myRow.T = n * 1.0;
            myRow.Vf = 2.0;
            myRow.Im = 4.0;

            myTable.Add(myRow);

            n++;
        }
        end = DateTime.Now;
        System.TimeSpan diff = end.Subtract(start);
        label2.Text = diff.Seconds.ToString();
        label4.Text = diff.Milliseconds.ToString();

        dataGridView1.DataSource = myTable;
    }

    //define the list as it is done on buttons 3 & 4 but use the static struct
    private void button2_Click(object sender, EventArgs e)
    {
        Type myType = typeof(DataRow);

        Type listType = typeof(List<>);

        Type myListType = listType.MakeGenericType(myType);

        IList myTable = (IList)Activator.CreateInstance(myListType);

        DataRow bRow = new DataRow();

        int n = 0;
        start = DateTime.Now;
        while (n < 100000)
        {
            bRow.t = n * 1.0;
            bRow.vf = 2.0;
            bRow.im = 4.0;
            myTable.Add(bRow);

            n++;
        }
        end = DateTime.Now;
        System.TimeSpan diff = end.Subtract(start);
        label2.Text = diff.Seconds.ToString();
        label4.Text = diff.Milliseconds.ToString();
        dataGridView1.DataSource = myTable;

    }

    //Create assy at runtime and load dll
    private void button3_Click(object sender, EventArgs e)
    {
        Type myType = CreateDynRow();
        Assembly myAssy = Assembly.LoadFrom("DynaRowAssy.dll");
        Type myRow = myAssy.GetType("DynaRow");

        Type listType = typeof(List<>);

        Type myListType = listType.MakeGenericType(myRow);

        IList myTable = (IList)Activator.CreateInstance(myListType);

        FieldInfo piT = myRow.GetField("t");
        FieldInfo piVf = myRow.GetField("vf");
        FieldInfo piIm = myRow.GetField("im");

        ValueType aRow = (ValueType)Activator.CreateInstance(myRow);

        int n = 0;
        start = DateTime.Now;
        while (n < 100000)
        {
            piT.SetValue(aRow, 1 * n);
            piVf.SetValue(aRow, 2.0);
            piIm.SetValue(aRow, 4.0);
            myTable.Add(aRow);

            n++;
        }
        end = DateTime.Now;
        System.TimeSpan diff = end.Subtract(start);
        label2.Text = diff.Seconds.ToString();
        label4.Text = diff.Milliseconds.ToString();
        dataGridView1.DataSource = myTable;
    }

    //create assy at runtime in memory
    private void button4_Click(object sender, EventArgs e)
    {
        //build the assembly
        Type myType = CreateDynRow();

        Type listType = typeof(List<>);

        Type myListType = listType.MakeGenericType(myType);

        IList myTable = (IList)Activator.CreateInstance(myListType);

        FieldInfo piT = myType.GetField("t");
        FieldInfo piVf = myType.GetField("vf");
        FieldInfo piIm = myType.GetField("im");

        ValueType aRow = (ValueType)Activator.CreateInstance(myType);

        int n = 0;
        start = DateTime.Now;
        while (n < 100000)
        {
            piT.SetValue(aRow, 1 * n);
            piVf.SetValue(aRow, 2.0);
            piIm.SetValue(aRow, 4.0);
            myTable.Add(aRow);

            n++;
        }
        end = DateTime.Now;
        System.TimeSpan diff = end.Subtract(start);
        label2.Text = diff.Seconds.ToString();
        label4.Text = diff.Milliseconds.ToString();
        dataGridView1.DataSource = myTable;
    }

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

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

发布评论

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

评论(3

不必你懂 2024-08-22 09:02:25

这不是(主要)动态创建:它是使用反射(FieldInfo.SetValue),使得button3和button4版本比可以编译调用时慢。

解决这个问题的一种可能方法是声明一个您的代码可以使用的接口编译并让动态类型实现此接口。您仍然会通过反射实例化和查询该接口的动态类型,但之后它应该与“静态”引用一样快。

It's not (primarily) the dynamic creation: it's the use of reflection (FieldInfo.SetValue) that makes the button3 and button4 versions slower than when the calls can be compiled in.

A possible way around this is to declare an interface that your code can compile against, and have the dynamic type implement this interface. You'll still take a small hit instantiating and querying the dynamic type for that interface via reflection, but after that it should be as fast as the "static" references.

月亮坠入山谷 2024-08-22 09:02:25

简单答案:正在执行更多代码来动态创建对象。

反射总是比预先定义类型然后直接使用该对象要慢。您要求运行时为您做更多的工作,而不是预先指定所有内容。根据您使用的反射功能...您的代码会变慢。

如果您需要详细信息,请检查代码生成的 IL。这应该给你整个故事。

Simple Answer: More code is being executed to dynamicaly create the object.

Reflection is always going to be slower than defining the type up front and then working with that object directly. You're asking the runtime to do a lot more work for you rather than specifying everything up front. Depending on which Reflection features you're using...your code will be slower.

If you want the specifics, examine the IL that your code generates. That should give you the whole story.

诠释孤独 2024-08-22 09:02:25

这就是我们的想法。它几乎与静态定义的情况一样快:

// Dynamically create DataRow derived from ValueType, 
// List of DataRows, 
// Delegates to properties
//  

private void button4_Click(object sender, EventArgs e)
{
    Type myType = CreateDynRow();  // dynamic version of DataRow, see above
    Type myListType = typeof(List<>).MakeGenericType(myType);
    IList myTable = (IList)Activator.CreateInstance(myListType);
    ValueType myRowBuffer = (ValueType)Activator.CreateInstance(myType);

    var mySet_TDelegate = myRowBuffer.GetInstanceInvoker<Action<Double>>("set_T");
    var mySet_ImDelegate = myRowBuffer.GetInstanceInvoker<Action<Double>>("set_Im");
    var mySet_VfDelegate = myRowBuffer.GetInstanceInvoker<Action<Double>>("set_Vf");

    stopWatch.Reset();
    stopWatch.Start();
    for (int n = 0; n < rowCount; n++)
    {
        mySet_TDelegate(1.0 * n);
        mySet_ImDelegate(4.0);
        mySet_VfDelegate(2.0);

        myTable.Add(myRowBuffer);
    }
    stopWatch.Stop();
    label1.Text = String.Format("{0}", stopWatch.ElapsedMilliseconds);

    dataGridView1.DataSource = myTable;
}

感谢您的帮助。顺便说一下,我们是用 Justin 的 & 来的。马克的回答。 GetInstanceInvoker 来自 Kenneth Xu 的 Common.Reflection 类。

Here's what we came up with. It is almost as fast as the statically defined case:

// Dynamically create DataRow derived from ValueType, 
// List of DataRows, 
// Delegates to properties
//  

private void button4_Click(object sender, EventArgs e)
{
    Type myType = CreateDynRow();  // dynamic version of DataRow, see above
    Type myListType = typeof(List<>).MakeGenericType(myType);
    IList myTable = (IList)Activator.CreateInstance(myListType);
    ValueType myRowBuffer = (ValueType)Activator.CreateInstance(myType);

    var mySet_TDelegate = myRowBuffer.GetInstanceInvoker<Action<Double>>("set_T");
    var mySet_ImDelegate = myRowBuffer.GetInstanceInvoker<Action<Double>>("set_Im");
    var mySet_VfDelegate = myRowBuffer.GetInstanceInvoker<Action<Double>>("set_Vf");

    stopWatch.Reset();
    stopWatch.Start();
    for (int n = 0; n < rowCount; n++)
    {
        mySet_TDelegate(1.0 * n);
        mySet_ImDelegate(4.0);
        mySet_VfDelegate(2.0);

        myTable.Add(myRowBuffer);
    }
    stopWatch.Stop();
    label1.Text = String.Format("{0}", stopWatch.ElapsedMilliseconds);

    dataGridView1.DataSource = myTable;
}

Thanks for your help. By the way, we got here using Justin's & Mark's answers. And GetInstanceInvoker is from Kenneth Xu's Common.Reflection class.

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