拳击会导致性能问题吗?如何防止拳击
本文关键字:拳击 何防止 性能 问题 | 更新日期: 2023-09-27 17:56:49
装箱会导致我的代码出现性能问题吗?如何防止拳击?
void Main()
{
AreEqual<int>(12, 13);
}
public static bool AreEqual<T>(T a, T b)
{
return a.Equals(b);
}
IL:
IL_0000: nop
IL_0001: ldc.i4.s 0C
IL_0003: ldc.i4.s 0D
IL_0005: call UserQuery.AreEqual
IL_000A: pop
IL_000B: ret
AreEqual:
IL_0000: nop
IL_0001: ldarga.s 00
IL_0003: ldarg.1
IL_0004: box 01 00 00 1B
IL_0009: constrained. 01 00 00 1B
IL_000F: callvirt System.Object.Equals
IL_0014: stloc.0 // CS$1$0000
IL_0015: br.s IL_0017
IL_0017: ldloc.0 // CS$1$0000
IL_0018: ret
装箱会导致我的代码出现性能问题吗?
只有你能回答这个问题。这是你的代码,这是你的代码的性能。对我来说,这不是问题,对你来说,可能是。
如何防止拳击?
通过强制编译器选择正确的重载。您的初始代码调用 object.Equals(object)
(在 Int32.Equals(object)
中被覆盖),因为这是唯一适用于每个不受约束T
的方法,这需要对您传递的int
参数进行装箱。
Int32.Equals(Int32)
实现IEquatable<T>.Equals(T)
,所以把它作为约束:
private static bool AreEqualEquatable<T>(T a, T b)
where T : IEquatable<T>
{
return a.Equals(b);
}
编译到此 IL:
IL_0000: nop
IL_0001: ldarga.s a
IL_0003: ldarg.1
IL_0004: constrained. !!T
IL_000a: callvirt instance bool class [mscorlib]System.IEquatable`1<!!T>::Equals(!0)
IL_000f: stloc.0
IL_0010: br.s IL_0012
IL_0012: ldloc.0
IL_0013: ret
因为编译器会尝试找到最专业的重载,在本例中为 IEquatable<T>.Equals(T)
.
有时有,通常不会。
您无法以这种方式真正预测性能问题。您是否有一个太慢的特定程序,并且您怀疑问题出在拳击上?
请参阅此隐藏功能,该功能可用作解决方法。但是 - 一如既往 - 确保这不是过早的优化。
示例代码:
static void foo<T>(ref T value) {
//This is the ONLY way to treat value as bool, without boxing/unboxing objects
if(value is bool) {
TypedReference reference = __makeref(value); //get reference
bool boolVal = __refvalue(reference,bool); //get primitive value
__refvalue(reference, bool) = !boolVal; //set primitive value
} else {
value = default(T);
}
}
我从这个线程中获取了部分代码
执行任务所做的任何其他操作都会降低性能,性能下降是一回事,性能问题是另一回事。如果您尝试实现包含数百万数据的高速数据结构,可能会导致性能问题,但如果您只是编写一个在数据库和网络上执行许多查询的信息系统,那么我认为装箱不会给您带来性能问题。
您应该始终分析您的应用程序,并查看究竟在哪里损害性能。
因此,如果您尝试比较两个整数,则操作为 (a == b)。如果您为此编写函数,则需要额外的函数调用。如果添加其他泛型方法、匿名类型、装箱、取消装箱...然后,所有这些附加操作都会降低性能。
如此处所述,您可以防止整数装箱。
这是一个基准
private static void Main(string[] args)
{
var sw1 = new Stopwatch();
bool b1 = true;
sw1.Start();
for (int i = 0; i < 10 * 1000 * 1000; i++)
{
b1 = b1 ^ AreEqual(i, i + 1);
}
sw1.Stop();
Console.WriteLine(b1);
Console.WriteLine(sw1.ElapsedTicks);
var sw2 = new Stopwatch();
bool b2 = true;
sw2.Start();
for (int i = 0; i < 10 * 1000 * 1000; i++)
{
b2 = b2 ^ AreEqualEx(i, i + 1);
}
sw2.Stop();
Console.WriteLine(b2);
Console.WriteLine(sw2.ElapsedTicks);
}
public static bool AreEqual<T>(T a, T b)
{
return a.Equals(b);
}
public static bool AreEqualEx<T>(T a, T b) where T:IEquatable<T>
{
return a.Equals(b);
}
结果是
真
254379 真
35514