gpt4 book ai didi

c# - 为什么转换数组(向量)这么慢?

转载 作者:太空狗 更新时间:2023-10-29 19:48:06 25 4
gpt4 key购买 nike

我的印象是在 .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

Dropcasting 比任何一个 cast 运算符快约 18 倍。为什么数组的转换这么慢?对于像 string=>object 这样的普通对象,差异要小得多。

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 规范应该在不进行转换的情况下进行转换。

最佳答案

因为你在转换数组。

这 3 段 IL 代码的区别在于后两者添加了一个 IsInst 和一个 CastClass 操作。对类型知之甚少,因此 CLR 必须检查它是否是有效操作。这需要时间。

CastClass 和 IsInst 之间的细微差别可以解释为 CastClass 首先执行 null 检查并在参数为 null 时立即成功。

我怀疑速度变慢是因为您在数组之间进行转换。可能需要做更多的工作来确保数组转换有效。可能需要查看每个元素以确定它是否可以转换为目标元素类型。所以我猜测,JIT 不是在“内联”机器代码中执行所有这些操作,而是发出对验证函数的调用。

事实上,如果您运行性能分析,您会发现这确实是正在发生的事情。几乎 90% 的时间花在名为“JIT_ChkCastArray”的函数上。

关于c# - 为什么转换数组(向量)这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7589381/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com