gin*_*boy 14 c# performance types for-loop
(背景:为什么我应该在C#中使用int而不是字节或short)
为了满足我自己对使用"适当大小"整数与"优化"整数的优缺点的好奇心,我编写了以下代码,强化了我以前在.Net中对int性能的真实性(并在链接中对此进行了解释)以上)它是针对int性能而不是short或byte进行优化的.
DateTime t;
long a, b, c;
t = DateTime.Now;
for (int index = 0; index < 127; index++)
{
Console.WriteLine(index.ToString());
}
a = DateTime.Now.Ticks - t.Ticks;
t = DateTime.Now;
for (short index = 0; index < 127; index++)
{
Console.WriteLine(index.ToString());
}
b=DateTime.Now.Ticks - t.Ticks;
t = DateTime.Now;
for (byte index = 0; index < 127; index++)
{
Console.WriteLine(index.ToString());
}
c=DateTime.Now.Ticks - t.Ticks;
Console.WriteLine(a.ToString());
Console.WriteLine(b.ToString());
Console.WriteLine(c.ToString());
Run Code Online (Sandbox Code Playgroud)
这在......的范围内给出了大致一致的结果.
〜95万
〜2000000
〜1700000
这与我期望看到的一致.
但是当我尝试重复每个数据类型的循环时......
t = DateTime.Now;
for (int index = 0; index < 127; index++)
{
Console.WriteLine(index.ToString());
}
for (int index = 0; index < 127; index++)
{
Console.WriteLine(index.ToString());
}
for (int index = 0; index < 127; index++)
{
Console.WriteLine(index.ToString());
}
a = DateTime.Now.Ticks - t.Ticks;
Run Code Online (Sandbox Code Playgroud)
数字更像......
〜450
〜3100000
〜30万
我发现这令人费解.任何人都可以提供解释吗?
注意:为了比较,我喜欢将循环限制为127,因为字节值类型的范围.这也是一种好奇心而非生产代码微优化的行为.
Aar*_*ght 41
首先,它不是针对int
性能进行优化的.NET,它是优化的机器,因为32位是本机字大小(除非您使用的是x64,在这种情况下它是long
64位).
其次,你在每个循环中写入控制台 - 这比增加和测试循环计数器要昂贵得多,所以你不会在这里测量任何真实的东西.
第三,a的byte
范围最大为255,所以你可以循环254次(如果你试图做255,它会溢出而循环永远不会结束 - 但你不需要停在128).
第四,你没有做任何接近足够的迭代来进行分析.迭代128或甚至254次的紧密循环是没有意义的.你应该做的是将byte
/ short
/ int
循环放在另一个迭代次数很多的循环中,比如1000万,并检查结果.
最后,DateTime.Now
在计算中使用会在分析时产生一些定时"噪声".建议(并且更容易)使用秒表类.
最重要的是,在进行有效的性能测试之前,这需要进行许多更改.
以下是我认为更准确的测试程序:
class Program
{
const int TestIterations = 5000000;
static void Main(string[] args)
{
RunTest("Byte Loop", TestByteLoop, TestIterations);
RunTest("Short Loop", TestShortLoop, TestIterations);
RunTest("Int Loop", TestIntLoop, TestIterations);
Console.ReadLine();
}
static void RunTest(string testName, Action action, int iterations)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < iterations; i++)
{
action();
}
sw.Stop();
Console.WriteLine("{0}: Elapsed Time = {1}", testName, sw.Elapsed);
}
static void TestByteLoop()
{
int x = 0;
for (byte b = 0; b < 255; b++)
++x;
}
static void TestShortLoop()
{
int x = 0;
for (short s = 0; s < 255; s++)
++x;
}
static void TestIntLoop()
{
int x = 0;
for (int i = 0; i < 255; i++)
++x;
}
}
Run Code Online (Sandbox Code Playgroud)
这会在一个更大的循环(500万次迭代)中运行每个循环,并在循环内执行非常简单的操作(递增变量).我的结果是:
字节循环:经过时间= 00:00:03.8949910
短循环:经过时间= 00:00:03.9098782
Int循环:经过时间= 00:00:03.2986990
所以,没有明显的区别.
此外,确保您在发布模式下进行配置,许多人忘记并在调试模式下进行测试,这将显着降低准确性.
Jon*_*eet 12
大部分时间可能都花在了写入控制台上.尝试在循环中做一些不同的事情......
另外:
DateTime.Now
是一种衡量时间的坏方法.请System.Diagnostics.Stopwatch
改用Console.WriteLine
调用,一个127次迭代的循环就太短了,无法衡量.你需要运行循环大量的时间来获得一个合理的测量.这是我的基准:
using System;
using System.Diagnostics;
public static class Test
{
const int Iterations = 100000;
static void Main(string[] args)
{
Measure(ByteLoop);
Measure(ShortLoop);
Measure(IntLoop);
Measure(BackToBack);
Measure(DelegateOverhead);
}
static void Measure(Action action)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
action();
}
sw.Stop();
Console.WriteLine("{0}: {1}ms", action.Method.Name,
sw.ElapsedMilliseconds);
}
static void ByteLoop()
{
for (byte index = 0; index < 127; index++)
{
index.ToString();
}
}
static void ShortLoop()
{
for (short index = 0; index < 127; index++)
{
index.ToString();
}
}
static void IntLoop()
{
for (int index = 0; index < 127; index++)
{
index.ToString();
}
}
static void BackToBack()
{
for (byte index = 0; index < 127; index++)
{
index.ToString();
}
for (short index = 0; index < 127; index++)
{
index.ToString();
}
for (int index = 0; index < 127; index++)
{
index.ToString();
}
}
static void DelegateOverhead()
{
// Nothing. Let's see how much
// overhead there is just for calling
// this repeatedly...
}
}
Run Code Online (Sandbox Code Playgroud)
结果如下:
ByteLoop: 6585ms
ShortLoop: 6342ms
IntLoop: 6404ms
BackToBack: 19757ms
DelegateOverhead: 1ms
Run Code Online (Sandbox Code Playgroud)
(这是在上网本上 - 调整迭代次数,直到你得到合理的东西:)
这似乎表明它与您使用的类型基本没有显着差异.
小智 5
出于好奇,我从Aaronaught修改了一个程序,并以x86和x64模式进行了编译。奇怪,Int在x64中的运行速度快得多:
x86
字节循环:经过的时间= 00:00:00.8636454
短循环:经过的时间= 00:00:00.8795518
UShort循环:经过的时间= 00:00:00.8630357
Int循环:经过的时间= 00:00:00.5184154
UInt循环:经过的时间= 00:00:00.4950156
长循环:经过的时间= 00:00:01.2941183超长
循环:经过的时间= 00:00:01.3023409
x64
字节循环:经过的时间= 00:00:01.0646588
短循环:经过的时间= 00:00:01.0719330
UShort循环:经过的时间= 00:00:01.0711545
Int循环:经过的时间= 00:00:00.2462848
UInt循环:经过的时间= 00:00:00.4708777
长循环:经过的时间= 00:00:00.5242272超长
循环:经过的时间= 00:00:00.5144035