C# 铸型性能
两者之间是否存在可测量的性能差异C# 铸型性能,c#,.net,performance,types,C#,.net,Performance,Types,两者之间是否存在可测量的性能差异 ((TypeA) obj).method1(); ((TypeA) obj).method2(); ((TypeA) obj).method3(); 及 什么时候用了很多次 我经常看到这样的事情 if (((TextBox)sender).Text.Contains('.') || ((TextBox)sender).Text.Contains(',')) 不知道这是否是对性能的浪费 如果用很少的其他工作完成数十亿次,那么它可能是可测量的。我不知道CLR是否
((TypeA) obj).method1();
((TypeA) obj).method2();
((TypeA) obj).method3();
及
什么时候用了很多次
我经常看到这样的事情
if (((TextBox)sender).Text.Contains('.') || ((TextBox)sender).Text.Contains(','))
不知道这是否是对性能的浪费 如果用很少的其他工作完成数十亿次,那么它可能是可测量的。我不知道CLR是否会有效缓存强制转换工作的事实,因此它不需要再次执行该操作-如果现在不执行,它可能会在以后的版本中执行。它可以在64位JIT中实现,但不能在32位版本中实现,反之亦然——你明白了。不过,我怀疑它是否会对普通代码产生重大影响
就我个人而言,我更喜欢第二种形式的可读性,这一点到目前为止更为重要。@dkson:我测试了两种方法。以下是我在电脑上找到的内容: 他们的表现差不多。事实上,我发现第二种方法稍微慢一点。原因(我相信)是额外变量和初始演员的成本。当然,如果您使用了足够的强制转换,您可能会收回性能成本。看起来,只有在保存20-30次演员阵容后,您才能在性能方面实现收支平衡 以下是最近两次测试运行的结果:
TestMuliCast\_3x: 00:00:00.5970000
TestSingleCast\_3x: 00:00:00.6020000
TestMuliCast\_30x: 00:00:06.0930000
TestSingleCast\_30x: 00:00:06.0480000
TestMuliCast\_3x: 00:00:00.6120000
TestSingleCast\_3x: 00:00:00.6250000
TestMuliCast\_30x: 00:00:06.5490000
TestSingleCast\_30x: 00:00:06.4440000
我还测试了castclass
和isinst
之间的差异。根据我读到的内容:
我认为即使没有例外,isinst也会比castclass快。然而,在创建了自己的基准测试之后,我发现isinst比castclass稍微慢一些。非常有趣。以下是我的结果:
TestEmptyLoop: 00:00:00.0870000
TestDCast\_castclass: 00:00:00.2640000
TestDCast\_isinst: 00:00:00.3780000
TestEmptyLoop: 00:00:00.0870000
TestDCast\_castclass: 00:00:00.2600000
TestDCast\_isinst: 00:00:00.3750000
所以,斯基特先生,我被纠正了
环境:
Windows Vista最大磁芯速度3.2Ghz
.NET Framework v2.0.50727 以下是我创建和运行的基准测试的完整来源: (利用Jon Skeets微基准框架)
+我还认为类型转换应该使用“as”操作符完成,并在以后检查null,除非您希望抛出异常。同意,尽管我经常看到在应该使用转换时使用“as”。通常情况下,“错误类型”==“bug”,在这种情况下,简单强制转换是正确的方法。在性能方面,“as”操作符导致csc发出“isinst”操作码(与bog样式的“Castclass”操作码相比)在数百万次的石膏测试中,它的速度快了8倍。@novatrust:我已经多次测试过了,但从未见过它有明显的速度。您测试的是.NET的哪个版本?这样的说法需要证据,依我看……(当然,如果强制转换失败,isinst会快得多,但我们讨论的是一种非常不同的情况,两者的结果完全不同。当强制转换成功,并且是直接强制转换而不是用户转换时,性能应该差不多。)对于所示的回路,多回路与单回路的计时差异约为1%,这并不奇怪,应在测试方法的噪声比范围内考虑。我认为C#编译器或CLR优化这两种方法是相同的。检查IL或本机反汇编程序会很有趣。此外,并非所有类型转换都是相等的,并且可以跨越类层次结构边界或涉及泛型,有时当行为被重写时,这可能会很昂贵。
TestEmptyLoop: 00:00:00.0870000
TestDCast\_castclass: 00:00:00.2640000
TestDCast\_isinst: 00:00:00.3780000
TestEmptyLoop: 00:00:00.0870000
TestDCast\_castclass: 00:00:00.2600000
TestDCast\_isinst: 00:00:00.3750000
using System;
using System.Collections;
public class CastingBenchmark
{
static Int64 Iterations=100000000;
static Int64 TestWork = 0;
public static void Init(string[] args)
{
if (args.Length>0)
Iterations = Int64.Parse(args[0]);
}
public static void Reset()
{
TestWork = 0;
}
internal class BaseType { public void TestBaseMethod() { TestWork++; } }
internal class DerivedType : BaseType {
public void TestDerivedMethod() { TestWork++; }
public void TestDerivedMethod2() { TestWork++; }
public void TestDerivedMethod3() { TestWork++; }
}
[Benchmark]
public static void TestMuliCast_3x()
{
BaseType TestBaseType = new DerivedType();
for (int x = 0; x < Iterations; x++)
{
((DerivedType)TestBaseType).TestDerivedMethod();
((DerivedType)TestBaseType).TestDerivedMethod2();
((DerivedType)TestBaseType).TestDerivedMethod3();
}
}
[Benchmark]
public static void TestSingleCast_3x()
{
BaseType TestBaseType = new DerivedType();
for (int x = 0; x < Iterations; x++)
{
DerivedType TestDerivedType = (DerivedType)TestBaseType;
TestDerivedType.TestDerivedMethod();
TestDerivedType.TestDerivedMethod2();
TestDerivedType.TestDerivedMethod3();
}
}
[Benchmark]
public static void TestMuliCast_30x()
{
BaseType TestBaseType = new DerivedType();
for (int x = 0; x < Iterations; x++)
{
//Simulate 3 x 10 method calls while casting
for (int y = 0; y < 10; y++) {
((DerivedType)TestBaseType).TestDerivedMethod();
((DerivedType)TestBaseType).TestDerivedMethod2();
((DerivedType)TestBaseType).TestDerivedMethod3();
}
}
}
[Benchmark]
public static void TestSingleCast_30x()
{
BaseType TestBaseType = new DerivedType();
for (int x = 0; x < Iterations; x++)
{
DerivedType TestDerivedType = (DerivedType)TestBaseType;
//Simulate 3 x 10 method calls on already-cast object
for (int y = 0; y < 10; y++)
{
TestDerivedType.TestDerivedMethod();
TestDerivedType.TestDerivedMethod2();
TestDerivedType.TestDerivedMethod3();
}
}
}
[Benchmark]
public static void TestEmptyLoop()
{
for (int x = 0; x < Iterations; x++)
{
}
}
[Benchmark]
public static void TestDCast_castclass()
{
BaseType TestDerivedType = new DerivedType();
for (int x = 0; x < Iterations; x++)
{
((DerivedType)TestDerivedType).TestDerivedMethod();
}
}
[Benchmark]
public static void TestDCast_isinst()
{
BaseType TestDerivedType = new DerivedType();
for (int x = 0; x < Iterations; x++)
{
(TestDerivedType as DerivedType).TestDerivedMethod();
}
}
}
method public hidebysig static void TestDCast_isinst() cil managed
{
.custom instance void BenchmarkAttribute::.ctor()
.maxstack 2
.locals init (
[0] class CastingBenchmark/BaseType TestDerivedType,
[1] int32 x)
L_0000: newobj instance void CastingBenchmark/DerivedType::.ctor()
L_0005: stloc.0
L_0006: ldc.i4.0
L_0007: stloc.1
L_0008: br.s L_0019
L_000a: ldloc.0
L_000b: isinst CastingBenchmark/DerivedType
L_0010: callvirt instance void CastingBenchmark/DerivedType::TestDerivedMethod()
L_0015: ldloc.1
L_0016: ldc.i4.1
L_0017: add
L_0018: stloc.1
L_0019: ldloc.1
L_001a: conv.i8
L_001b: ldsfld int64 CastingBenchmark::Iterations
L_0020: blt.s L_000a
L_0022: ret
}
.method public hidebysig static void TestDCast_castclass() cil managed
{
.custom instance void BenchmarkAttribute::.ctor()
.maxstack 2
.locals init (
[0] class CastingBenchmark/BaseType TestDerivedType,
[1] int32 x)
L_0000: newobj instance void CastingBenchmark/DerivedType::.ctor()
L_0005: stloc.0
L_0006: ldc.i4.0
L_0007: stloc.1
L_0008: br.s L_0019
L_000a: ldloc.0
L_000b: castclass CastingBenchmark/DerivedType
L_0010: callvirt instance void CastingBenchmark/DerivedType::TestDerivedMethod()
L_0015: ldloc.1
L_0016: ldc.i4.1
L_0017: add
L_0018: stloc.1
L_0019: ldloc.1
L_001a: conv.i8
L_001b: ldsfld int64 CastingBenchmark::Iterations
L_0020: blt.s L_000a
L_0022: ret
}