Tenía la impresión de que en .NET casting (no convertir) es muy barato y rápido. Sin embargo, este no parece ser el caso para array. Estoy tratando de hacer un elenco muy simple aquí, tomar una T1 [] y lanzar como T2 []. donde T1: T2.¿Por qué los arrays de arrays (vectores) son tan lentos?
Hay 3 maneras de hacer esto y yo los llamo a la siguiente ::
DropCasting: T2[] array2 = array;
CastClass: (T2[])array;
IsInst: array as T2[];
Y creado métodos para hacer esto, por desgracia, C# parece crear un código bastante extraño dependiendo de si esto es genérico o no. (Si su DropCasting genérico utiliza el operador castclass. Y en ambos casos se niega a emitir un operador 'como' cuando T1: T2.
De todos modos, escribí algunos métodos dinámicos y probé algunos resultados sorprendentes (string [] => Object []):.?
DropCast : 223ms
IsInst : 3648ms
CastClass: 3732ms
Dropcasting fue ~ 18 veces más rápido que cualquiera de los operadores de conversión ¿por qué está lanzando tan lento para las matrices para los objetos normales como cadena => objeto, la diferencia fue mucho menor severo.
DropCast : 386ms
IsInst : 611ms
CastClass: 519ms
Código de referencia bel ow:
class Program
{
static readonly String[] strings = Enumerable.Range(0, 10).Select(x => x.ToString()).ToArray();
static Func<string[], object[]> Dropcast = new Func<Func<string[], object[]>>(
() =>
{
var method = new DynamicMethod("DropCast", typeof(object[]), new[] { typeof(object), typeof(string[]) },true);
var ilgen = method.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(Func<string[], object[]>)) as Func<string[], object[]>;
})();
static Func<string[], object[]> CastClass = new Func<Func<string[], object[]>>(
() =>
{
var method = new DynamicMethod("CastClass", typeof(object[]), new[] { typeof(object), typeof(string[]) },true);
var ilgen = method.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Castclass, typeof(object[]));
ilgen.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(Func<string[], object[]>)) as Func<string[], object[]>;
})();
static Func<string[], object[]> IsInst = new Func<Func<string[], object[]>>(
() =>
{
var method = new DynamicMethod("IsInst", typeof(object[]), new[] { typeof(object), typeof(string[]) },true);
var ilgen = method.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Isinst, typeof(object[]));
ilgen.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(Func<string[], object[]>)) as Func<string[], object[]>;
})();
static Func<string[], object[]>[] Tests = new Func<string[], object[]>[]{
Dropcast,
IsInst,
CastClass
};
static void Main(string[] args)
{
int maxMethodLength = Tests.Select(x => GetMethodName(x.Method).Length).Max();
RunTests(1, false, maxMethodLength);
RunTests(100000000, true, maxMethodLength);
}
static string GetMethodName(MethodInfo method)
{
return method.IsGenericMethod ?
string.Format(@"{0}<{1}>", method.Name, string.Join<Type>(",", method.GetGenericArguments())) : method.Name;
}
static void RunTests(int count, bool displayResults, int maxLength)
{
foreach (var action in Tests)
{
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < count; i++)
{
action(strings);
}
sw.Stop();
if (displayResults)
{
Console.WriteLine("{0}: {1}ms", GetMethodName(action.Method).PadRight(maxLength),
((int)sw.ElapsedMilliseconds).ToString().PadLeft(6));
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
}
Editar antes de que alguien pide el mismo es cierto para cosas como int [] -> uint [], que las especificaciones CLR sea echado sin conversión.
El punto era masajear el IL derecho.En un método extremadamente trivial como '() => strings como objeto [];' el compilador descartará el método 'as'. La creación del método dinámico solo se ejecuta una vez en el '.cctor' del programa. Después de eso, cada método es solo el blob de IL. También agregué una "instancia" a cada método dinámico (el parámetro del objeto), solo para evitar la mezcla de thunk al usar un delegado en un método estático. –
sí, me perdí la segunda capa de funcs al leer la primera vez. Entonces eliminé mi comentario. ;) –
Cubierto varias veces, solo puede encontrar la página de inicio: http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-inc-c-part-two -array-covariance.aspx –