我搜索了* operator和Math.BigMul method之间的差异,却一无所获。所以我决定尝试相互测试他们的效率。请考虑以下代码:
public class Program
{
static void Main()
{
Stopwatch MulOperatorWatch = new Stopwatch();
Stopwatch MulMethodWatch = new Stopwatch();
MulOperatorWatch.Start();
// Creates a new MulOperatorClass to perform the start method 100 times.
for (int i = 0; i < 100; i++)
{
MulOperatorClass mOperator = new MulOperatorClass();
mOperator.start();
}
MulOperatorWatch.Stop();
MulMethodWatch.Start();
for (int i = 0; i < 100; i++)
{
MulMethodClass mMethod = new MulMethodClass();
mMethod.start();
}
MulMethodWatch.Stop();
Console.WriteLine("Operator = " + MulOperatorWatch.ElapsedMilliseconds.ToString());
Console.WriteLine("Method = " + MulMethodWatch.ElapsedMilliseconds.ToString());
Console.ReadLine();
}
public class MulOperatorClass
{
public void start()
{
List<long> MulOperatorList = new List<long>();
for (int i = 0; i < 15000000; i++)
{
MulOperatorList.Add(i * i);
}
}
}
public class MulMethodClass
{
public void start()
{
List<long> MulMethodList = new List<long>();
for (int i = 0; i < 15000000; i++)
{
MulMethodList.Add(Math.BigMul(i,i));
}
}
}
}
总结一下:我创建了两个类 - MulMethodClass
和MulOperatorClass
,它们同时执行start
方法,该方法填充了List<long
类型的变量。值i multiply by i
多次。这些方法之间的唯一区别是在运算符类中使用* operator
,以及在方法类中使用Math.BigMul
。
我正在创建每个类的100个实例,只是为了防止和溢出列表(我无法创建1000000000个项目列表)。
然后,我测量100个类中每个类执行所需的时间。结果很奇怪:我做了大约15次这个过程,平均结果是(以毫秒为单位):运营商= 20357
方法= 24579
大约4.5秒的差异,我觉得很多。我查看了BigMul method的源代码 - 它使用了* operator
,实际上也做了同样的事情。
所以,对于我的问题:
我只是好奇:)
答案 0 :(得分:2)
微观标记是艺术。你是对的,x86上的方法慢了大约10%。 x64上的速度相同。请注意,您必须将两个长整数乘以((long)i) * ((long)i)
,因为它是BigMul
!
现在,如果你想要microbenchmark,一些简单的规则:
A)不要在基准测试代码中分配内存......你不希望GC运行(你正在扩大List<>
)
B)在定时区域之外预分配内存(在运行代码之前创建具有正确容量的List<>
)
C)在对基准测试之前至少运行一次或两次方法。
D)尝试不做任何事情,除了你的基准测试,但强迫编译器运行你的代码。例如,基于操作的结果检查始终为真的条件,如果为假则抛出异常通常足以欺骗编译器。
static void Main()
{
// Check x86 or x64
Console.WriteLine(IntPtr.Size == 4 ? "x86" : "x64");
// Check Debug/Release
Console.WriteLine(IsDebug() ? "Debug, USELESS BENCHMARK" : "Release");
// Check if debugger is attached
Console.WriteLine(System.Diagnostics.Debugger.IsAttached ? "Debugger attached, USELESS BENCHMARK!" : "Debugger not attached");
// High priority
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Stopwatch MulOperatorWatch = new Stopwatch();
Stopwatch MulMethodWatch = new Stopwatch();
// Prerunning of the benchmarked methods
MulMethodClass.start();
MulOperatorClass.start();
{
// No useless method allocation here
MulMethodWatch.Start();
for (int i = 0; i < 100; i++)
{
MulMethodClass.start();
}
MulMethodWatch.Stop();
}
{
// No useless method allocation here
MulOperatorWatch.Start();
for (int i = 0; i < 100; i++)
{
MulOperatorClass.start();
}
MulOperatorWatch.Stop();
}
Console.WriteLine("Operator = " + MulOperatorWatch.ElapsedMilliseconds.ToString());
Console.WriteLine("Method = " + MulMethodWatch.ElapsedMilliseconds.ToString());
Console.ReadLine();
}
public class MulOperatorClass
{
// The method is static. No useless memory allocation
public static void start()
{
for (int i = 2; i < 15000000; i++)
{
// This condition will always be false, but the compiler
// won't be able to remove the code
if (((long)i) * ((long)i) == ((long)i))
{
throw new Exception();
}
}
}
}
public class MulMethodClass
{
public static void start()
{
// The method is static. No useless memory allocation
for (int i = 2; i < 15000000; i++)
{
// This condition will always be false, but the compiler
// won't be able to remove the code
if (Math.BigMul(i, i) == i)
{
throw new Exception();
}
}
}
}
private static bool IsDebug()
{
// Taken from http://stackoverflow.com/questions/2104099/c-sharp-if-then-directives-for-debug-vs-release
object[] customAttributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);
if ((customAttributes != null) && (customAttributes.Length == 1))
{
DebuggableAttribute attribute = customAttributes[0] as DebuggableAttribute;
return (attribute.IsJITOptimizerDisabled && attribute.IsJITTrackingEnabled);
}
return false;
}
E)如果您确定您的代码没问题,请尝试更改测试的顺序
F)将您的程序置于更高优先级
但要高兴: - )
至少另一个人有同样的问题,写了一篇博客文章:http://reflectivecode.com/2008/10/mathbigmul-exposed/
他做了同样的错误。