Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I speed up instantiating a large collection of objects?

Tags:

performance

c#

The code below is extremely slow for tables of any significant size. (100, 1000, etc...) The culprit is instantiating my objects with new T(). Note that this isn't my finalized code, I've just broken parts of it out in order to more easily profile. Instantiation and initialization will happen together once I refactor the code back into shape.

Is there any way to speed this up? I'm probably forgetting something really simple, or maybe I'm boned. Hopefully, the former.

public static IList<T> ToList<T>(this DataTable table) where T : Model, new()
{
    T[] entities = new T[table.Rows.Count];

    // THIS LOOP IS VERY VERY SLOW
    for (int i = 0; i < table.Rows.Count; i++)
        entities[i] = new T();

    // THIS LOOP IS FAST
    for (int i = 0; i < table.Rows.Count; i++)
        entities[i].Init(table, table.Rows[i]);

    return new List<T>(entities);
}

edit for more info:

The constructor of any given ModelType will look like this:

public ModelType()
{
    _modelInfo = new ModelTypeInfo();
}

The constructor of any given ModelTypeInfo will simply set some string and string[] values, and that class' only job is to provide the values set.

edit for even more info:

Since it seems to be a hot topic, here is what my method looks like for reals before breaking out object construction and initialization:

public static IList<T> ToList<T>(this DataTable table, ModelInfo modelInfo) where T : Model, new()
{
    var tempRepository = new Repository<T>(modelInfo);

    var list = new List<T>();
    foreach (DataRow row in table.Rows)
        list.Add(tempRepository.FromData(table, row));

    return list;
}
like image 965
Samantha Branham Avatar asked Jul 14 '09 21:07

Samantha Branham


1 Answers

Under the covers, new T() generates a call to System.Activator.CreateInstance<T>(), which is (reflectively) slow:

L_0012: ldc.i4.0 
L_0013: stloc.1 
L_0014: br.s L_0026
L_0016: ldloc.0 
L_0017: ldloc.1 
L_0018: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
L_001d: stelem.any !!T
L_0022: ldloc.1 
L_0023: ldc.i4.1 
L_0024: add 
L_0025: stloc.1 

You may wish to consider passing in a construction delegate instead.

like image 137
Jeffrey Hantin Avatar answered Oct 09 '22 16:10

Jeffrey Hantin