我的印象是在.NET中(非转换)非常便宜且快速.但是,这似乎不是阵列的情况.我想在这里做一个非常简单的演员,拿一个T1 []并演员为T2 [].其中T1:T2.
有3种方法可以做到这一点,我称之为以下::
DropCasting: T2[] array2 = array;
CastClass: (T2[])array;
IsInst: array as T2[];
Run Code Online (Sandbox Code Playgroud)
我创建了这样做的方法,不幸的是,C#似乎创建了一些相当奇怪的代码,具体取决于它是否是通用的.(如果它的通用DropCasting使用了castclass运算符.在两种情况下,当T1:T2时拒绝发出'as'运算符.
无论如何,我写了一些动态方法,我测试了一些令人惊讶的结果(string [] => object []):
DropCast : 223ms
IsInst : 3648ms
CastClass: 3732ms
Run Code Online (Sandbox Code Playgroud)
垂直投射比任何一个投射操作员快约18倍.为什么阵列的播放速度如此之慢?对于像string => object这样的普通对象,差异要小得多.
DropCast : 386ms
IsInst : 611ms
CastClass: 519ms
Run Code Online (Sandbox Code Playgroud)
基准代码如下:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑之前任何人都要求int [] - > uint []这样的事情,其中clr规范应该在没有转换的情况下进行转换.
因为你正在投射数组。
这 3 个 IL 代码片段的区别在于,后两个片段添加了 IsInst 和 CastClass 操作。对这些类型知之甚少,因此 CLR 必须检查它是否是有效的操作。这需要时间。
CastClass 和 IsInst 之间的细微差别可以通过以下事实来解释:CastClass 首先执行 null 检查,如果参数为 null,则立即成功。
我怀疑速度减慢是因为您在数组之间进行转换。可能需要做更多的工作来确保数组转换有效。可能需要查看每个元素以查看它是否可以转换为目标元素类型。所以我猜测,JIT 不是在“内联”机器代码中完成所有这些操作,而是发出对验证函数的调用。
事实上,如果您运行性能分析,您会发现确实发生了这种情况。几乎 90% 的时间都花费在名为“JIT_ChkCastArray”的函数中。
| 归档时间: |
|
| 查看次数: |
414 次 |
| 最近记录: |