【问题标题】:Way to avoid either casting or additional allocations?避免强制转换或额外分配的方法?
【发布时间】:2015-05-22 01:31:23
【问题描述】:

假设我有一个类,它有一个 int 和一个由 10 个对象组成的数组。

假设我必须分配一百万个,这很昂贵,因为首先我必须分配容器对象,然后是 int,最后是数组。

为了避免分配,我可以使用一个包含 11 个对象的数组,第一个索引是 int。这样,我不必分配容器对象。经过分析,我发现这个代码的速度相当快。

我想知道我是否遗漏了什么,或者是否有更好的解决方案。要么我有容器对象,而且代码更漂亮、更通用,但由于额外的分配,它执行得更慢,或者我放弃自己,每次我想访问它时都必须将第 0 个索引转换为一个 int,并且失去代码的优雅。

编辑:对不起,我忘了提到这些数组有时会四处移动,因此我需要引用类型语义来避免复制整个数组而只是引用。出于这个原因,我认为我不能使用结构,除非也有解决方案。

【问题讨论】:

  • 就个人而言,我不会尝试优化这类事情。此外,除非数组包含一个使用与 int 相同数量的内存的对象,否则您会在数组内部分配额外的空间来浪费空间。
  • 此外,由于后期维护,在大多数情况下,提高可读性是一个巨大的优势。
  • 您是否正在尝试解决真正的性能问题?如果没有,请坚持使用漂亮的代码。
  • 这个程序已经运行了好几个星期。从那时起,我一直在做的就是优化。这对我来说非常重要。
  • 您需要分析您的应用程序以查看此分配实际上是性能问题还是您在浪费时间。

标签: c# arrays performance memory allocation


【解决方案1】:

尝试使用这样的结构:

    public struct Test
    {
        public int m_nObj;
        public object[] array;
    }
    ....
     Test[]  pTest = new Test[1000000];
     for(int i = 0 ; i <  1000000; i++)
     {
         pTest[i].array = new object[10];
     }

1234562 的平均时间 = 32ms;
struct 的平均时间 = 21ms;

总码:

class Program
{
     public struct Test
    {
        public int m_nObj;
        public object[] array;
    }
    public class Test2
    {
        public int m_nObj;
        public object[] array = new object[10];
    }
    public class Test3
    {
        public object[] array = new object[11];
    }

    static void Main(string[] args)
    {
         for (int j = 0; j < 100; j++)
        {
            GC.Collect();
            Stopwatch dtStart = new Stopwatch ();
            dtStart.Start();
            Test[] pTest = new Test[1000000];
            for (int i = 0; i < 1000000; i++)
            {
                pTest[i].array = new object[10];
            }

            dtStart.Stop();
            GC.Collect();
            Console.Out.WriteLine("Struct = " + dtStart.ElapsedMilliseconds);

            dtStart = new Stopwatch();
            dtStart.Start();
            Test2[] pTest2 = new Test2[1000000];
            for (int i = 0; i < 1000000; i++)
            {
                pTest2[i] = new Test2();
            }
            dtStart.Stop();
            GC.Collect();
            Console.Out.WriteLine("Class int = " + dtStart.ElapsedMilliseconds);

            dtStart = new Stopwatch();
            dtStart.Start();
            Test3[] pTest3 = new Test3[1000000];
            for (int i = 0; i < 1000000; i++)
            {
                pTest3[i] = new Test3();
            }
            dtStart.Stop();

            GC.Collect();
            Console.Out.WriteLine("Class no int = " + dtStart.ElapsedMilliseconds);
            Console.Out.WriteLine("=============================");
        } 
    }
}

Results:
Struct = 252.2253
int = 396.9113
no int = 262.9782

Struct = 266.8878
int = 399.845
no int = 473.181

Struct = 313.7979
int = 446.8496
no int = 411.5755

Struct = 364.6454
int = 389.0763
no int = 553.3433

Struct = 298.1766
int = 424.2794
no int = 441.8867

【讨论】:

  • 我看不出把它变成一个结构有什么帮助。无论如何,它都会被堆在一堆,因为它们有一百万个。
  • 是,但是没有ctor调用。
  • 这不是比仅仅拥有对象数组还慢吗?我会快速进行基准测试。
  • 不,更快,因为您正在跳过对隐式构造函数的函数调用
  • 您是否尝试过在函数中使用 ref 关键字通过 ref 而不是 value 传递结构。
猜你喜欢
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多