gpt4 book ai didi

.net - 为什么这里的 fastmember 看起来并不比反射快?

转载 作者:行者123 更新时间:2023-12-04 00:25:57 24 4
gpt4 key购买 nike

(这是通过 Twitter 上的一个问题,经许可在此处重新提问)

我正在尝试快速验证某些对象(以测试空值),我认为 FastMember 可能会有所帮助 - 但是,通过下面显示的测试,我发现性能要差得多。难道我做错了什么?

public class ValidateStuffTests
{
[Test]
public void Benchmark_speed()
{
var player = CreateValidStuffToTest();
_stopwatch.Start();
CharacterActions.IsValid(player);
_stopwatch.Stop();
Console.WriteLine(_stopwatch.Elapsed);
Assert.Less(_stopwatch.ElapsedMilliseconds, 10, string.Format("IsValid took {0} mileseconds", _stopwatch.Elapsed));

}

[Test]
public void When_Benchmark_fastMember()
{
var player = CreateValidStuffToTest();
_stopwatch.Start();
CharacterActions.IsValidFastMember(player);
_stopwatch.Stop();
Assert.Less(_stopwatch.ElapsedMilliseconds, 10, string.Format("IsValid took {0} mileseconds", _stopwatch.Elapsed));

}
}

public static class ValidateStuff
{
public static bool IsValid<T>(T actions)
{
var propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in propertyInfos)
{
if (property.GetValue(actions, null) == null)
return false;
}
return true;
}

public static bool IsValidFastMember<T>(T actions)
{
var typeAccessor = TypeAccessor.Create(typeof(T));

foreach (var property in typeAccessor.GetMembers())
{
if (typeAccessor[actions, property.Name] == null)
return false;
}
return true;
}
}

最佳答案

这里的主要问题是您将元编程的 1-off 成本包括在计时内。 FastMember 在处理类型并生成合适的 IL 时会产生一些开销,当然:所有 IL 生成层都需要在此之上进行 JIT。所以是的,使用一次:FastMember 可能看起来更贵。事实上,如果你只打算做一次这项工作,你就不会使用像 FastMember 这样的东西(反射会很好)。诀窍是做所有事情一次(在两个测试中)时间,这样第一次运行的表现就不会影响结果。而且,在性能方面,您通常需要多次运行。这是我的装备:

const int CYCLES = 500000;
[Test]
public void Benchmark_speed()
{
var player = CreateValidStuffToTest();
ValidateStuff.IsValid(player); // warm up
var _stopwatch = Stopwatch.StartNew();
for (int i = 0; i < CYCLES; i++)
{
ValidateStuff.IsValid(player);
}
_stopwatch.Stop();
Console.WriteLine(_stopwatch.Elapsed);
Console.WriteLine("Reflection: {0}ms", _stopwatch.ElapsedMilliseconds);
}

[Test]
public void When_Benchmark_fastMember()
{
var player = CreateValidStuffToTest();
ValidateStuff.IsValidFastMember(player); // warm up
var _stopwatch = Stopwatch.StartNew();
for (int i = 0; i < CYCLES; i++)
{
ValidateStuff.IsValidFastMember(player);
}
_stopwatch.Stop();
Console.WriteLine("FastMember: {0}ms", _stopwatch.ElapsedMilliseconds);
}

这表明 fast-member 快了一点,但没有我想要的那么多 - 600ms(反射)vs 200ms(FastMember);很可能 1.0.11 改变了太多偏向大类的东西(使用 1.0.10 只需要 130 毫秒)。我可能会发布一个 1.0.12,它对小类和大类使用不同的策略来进行补偿。

然而!在您的情况下,如果您只想测试 null ,我实际上会认真考虑直接通过 IL 优化该案例。

例如,下面的相同测试只需要 45 毫秒:
[Test]
public void When_Benchmark_Metaprogramming()
{
var player = CreateValidStuffToTest();
Console.WriteLine(ValidateStuff.IsValidMetaprogramming(player)); // warm up
var _stopwatch = Stopwatch.StartNew();
for (int i = 0; i < CYCLES; i++)
{
ValidateStuff.IsValidMetaprogramming(player);
}
_stopwatch.Stop();
Console.WriteLine("Metaprogramming: {0}ms", _stopwatch.ElapsedMilliseconds);
}

使用:
public static bool IsValidMetaprogramming<T>(T actions)
{
return !NullTester<T>.HasNulls(actions);
}

以及一些合适的疯狂元编程代码,用于测试任何给定的 T集中在一处:
static class NullTester<T>
{
public static readonly Func<T, bool> HasNulls;

static NullTester()
{
if (typeof(T).IsValueType)
throw new InvalidOperationException("Exercise for reader: value-type T");

var props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
var dm = new DynamicMethod("HasNulls", typeof(bool), new[] { typeof(T) });
var il = dm.GetILGenerator();

Label next, foundNull;
foundNull = il.DefineLabel();
Dictionary<Type, LocalBuilder> locals = new Dictionary<Type, LocalBuilder>();
foreach (var prop in props)
{
if (!prop.CanRead) continue;
var getter = prop.GetGetMethod(false);
if (getter == null) continue;
if (prop.PropertyType.IsValueType
&& Nullable.GetUnderlyingType(prop.PropertyType) == null)
{ // non-nullable value-type; can never be null
continue;
}
next = il.DefineLabel();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, getter);
if (prop.PropertyType.IsValueType)
{
// have a nullable-value-type on the stack; need
// to call HasValue, which means we need it as a local
LocalBuilder local;
if (!locals.TryGetValue(prop.PropertyType, out local))
{
local = il.DeclareLocal(prop.PropertyType);
locals.Add(prop.PropertyType, local);
}
il.Emit(OpCodes.Stloc, local);
il.Emit(OpCodes.Ldloca, local);
il.Emit(OpCodes.Call,
prop.PropertyType.GetProperty("HasValue").GetGetMethod(false));
il.Emit(OpCodes.Brtrue_S, next);
}
else
{
// is a class; fine if non-zero
il.Emit(OpCodes.Brtrue_S, next);
}
il.Emit(OpCodes.Br, foundNull);
il.MarkLabel(next);
}
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ret);
il.MarkLabel(foundNull);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ret);

HasNulls = (Func<T, bool>)dm.CreateDelegate(typeof(Func<T, bool>));
}
}

关于.net - 为什么这里的 fastmember 看起来并不比反射快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19124401/

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