内容简介:因为你正在构建数组.IL代码的3个片段之间的区别在于后两个添加了IsInst和CastClass操作.关于类型知之甚少,因此CLR必须检查它是否是有效的操作.这需要时间.CastClass和IsInst之间的细微差别可以解释为CastClass首先进行空检查,如果参数为null则立即成功.
我的印象是在.NET中(非转换)非常便宜且快速.但是,这似乎不是阵列的情况.我想在这里做一个非常简单的演员,拿一个T1 []并施放为T2 [].其中T1:T2.
有3种方法可以做到这一点,我称之为以下::
DropCasting: T2[] array2 = array; CastClass: (T2[])array; IsInst: array as T2[];
我创建了这样做的方法,不幸的是,C#似乎创建了一些相当奇怪的代码,具体取决于它是否是通用的. (如果它的通用DropCasting使用了castclass运算符.在两种情况下,当T1:T2时拒绝发出’as’运算符.
无论如何,我写了一些动态方法,我测试了一些令人惊讶的结果(string [] => object []):
DropCast : 223ms IsInst : 3648ms CastClass: 3732ms
垂直投射比任何一个投射运算符快约18倍.为什么阵列的播放速度如此之慢?
对于像string =>对象这样的普通对象,差异要小得多.
DropCast : 386ms IsInst : 611ms CastClass: 519ms
基准代码如下:
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(); } } }
编辑之前任何人都要求同样保持为int [] – > uint []之类的东西,clr specs应该在没有转换的情况下进行转换.
因为你正在构建数组.
IL代码的3个片段之间的区别在于后两个添加了IsInst和CastClass操作.关于类型知之甚少,因此CLR必须检查它是否是有效的操作.这需要时间.
CastClass和IsInst之间的细微差别可以解释为CastClass首先进行空检查,如果参数为null则立即成功.
我怀疑减速是因为你在数组之间进行投射.可能需要做更多工作才能确保数组转换有效.可能需要查看每个元素以查看它是否可以强制转换为目标元素类型.所以我猜想,JIT会发出对验证函数的调用,而不是在“内联”机器代码中执行所有操作.
实际上,如果您运行性能分析,您可以看到确实发生了什么.几乎90%的时间花在一个名为“JIT_ChkCastArray”的函数上.
翻译自:https://stackoverflow.com/questions/7589381/why-is-casting-arrays-vectors-so-slow
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。