查看某些内容(例如方法调用)接受代码的时间最长的方法是什么?
我猜的最容易和最快的是:
DateTime start = DateTime.Now;
{
// Do some work
}
TimeSpan timeItTook = DateTime.Now - start;
但这有多精确?还有更好的方法吗?
答案 0 :(得分:529)
更好的方法是使用秒表类:
using System.Diagnostics;
// ...
Stopwatch sw = new Stopwatch();
sw.Start();
// ...
sw.Stop();
Console.WriteLine("Elapsed={0}",sw.Elapsed);
答案 1 :(得分:159)
正如其他人所说,Stopwatch
是一个很好的课程。你可以用一个有用的方法包装它:
public static TimeSpan Time(Action action)
{
Stopwatch stopwatch = Stopwatch.StartNew();
action();
stopwatch.Stop();
return stopwatch.Elapsed;
}
(请注意Stopwatch.StartNew()
的使用。我更喜欢创建一个秒表,然后在简单性方面调用Start()
。)显然这会引起调用委托,但在绝大多数情况下不相关的案件。然后你会写:
TimeSpan time = StopwatchUtil.Time(() =>
{
// Do some work
});
您甚至可以为此设置ITimer
界面,StopwatchTimer,
CpuTimer
等实施可用。
答案 2 :(得分:73)
正如其他人所说,Stopwatch
应该是正确的工具。尽管如此,对它的改进却很少,具体见这个帖子:Benchmarking small code samples in C#, can this implementation be improved?。
基本上他的代码如下:
//prevent the JIT Compiler from optimizing Fkt calls away
long seed = Environment.TickCount;
//use the second Core/Processor for the test
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
//prevent "Normal" Processes from interrupting Threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
//prevent "Normal" Threads from interrupting this thread
Thread.CurrentThread.Priority = ThreadPriority.Highest;
//warm up
method();
var stopwatch = new Stopwatch()
for (int i = 0; i < repetitions; i++)
{
stopwatch.Reset();
stopwatch.Start();
for (int j = 0; j < iterations; j++)
method();
stopwatch.Stop();
print stopwatch.Elapsed.TotalMilliseconds;
}
另一种方法是依靠Process.TotalProcessTime
来衡量CPU保持忙碌的时间运行代码/进程,as shown here这可以反映更真实的情况,因为没有其他过程会影响测量。它的确如下:
var start = Process.GetCurrentProcess().TotalProcessorTime;
method();
var stop = Process.GetCurrentProcess().TotalProcessorTime;
print (end - begin).TotalMilliseconds;
的详细实施
我编写了一个帮助程序类,以易于使用的方式执行:
public class Clock
{
interface IStopwatch
{
bool IsRunning { get; }
TimeSpan Elapsed { get; }
void Start();
void Stop();
void Reset();
}
class TimeWatch : IStopwatch
{
Stopwatch stopwatch = new Stopwatch();
public TimeSpan Elapsed
{
get { return stopwatch.Elapsed; }
}
public bool IsRunning
{
get { return stopwatch.IsRunning; }
}
public TimeWatch()
{
if (!Stopwatch.IsHighResolution)
throw new NotSupportedException("Your hardware doesn't support high resolution counter");
//prevent the JIT Compiler from optimizing Fkt calls away
long seed = Environment.TickCount;
//use the second Core/Processor for the test
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
//prevent "Normal" Processes from interrupting Threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
//prevent "Normal" Threads from interrupting this thread
Thread.CurrentThread.Priority = ThreadPriority.Highest;
}
public void Start()
{
stopwatch.Start();
}
public void Stop()
{
stopwatch.Stop();
}
public void Reset()
{
stopwatch.Reset();
}
}
class CpuWatch : IStopwatch
{
TimeSpan startTime;
TimeSpan endTime;
bool isRunning;
public TimeSpan Elapsed
{
get
{
if (IsRunning)
throw new NotImplementedException("Getting elapsed span while watch is running is not implemented");
return endTime - startTime;
}
}
public bool IsRunning
{
get { return isRunning; }
}
public void Start()
{
startTime = Process.GetCurrentProcess().TotalProcessorTime;
isRunning = true;
}
public void Stop()
{
endTime = Process.GetCurrentProcess().TotalProcessorTime;
isRunning = false;
}
public void Reset()
{
startTime = TimeSpan.Zero;
endTime = TimeSpan.Zero;
}
}
public static void BenchmarkTime(Action action, int iterations = 10000)
{
Benchmark<TimeWatch>(action, iterations);
}
static void Benchmark<T>(Action action, int iterations) where T : IStopwatch, new()
{
//clean Garbage
GC.Collect();
//wait for the finalizer queue to empty
GC.WaitForPendingFinalizers();
//clean Garbage
GC.Collect();
//warm up
action();
var stopwatch = new T();
var timings = new double[5];
for (int i = 0; i < timings.Length; i++)
{
stopwatch.Reset();
stopwatch.Start();
for (int j = 0; j < iterations; j++)
action();
stopwatch.Stop();
timings[i] = stopwatch.Elapsed.TotalMilliseconds;
print timings[i];
}
print "normalized mean: " + timings.NormalizedMean().ToString();
}
public static void BenchmarkCpu(Action action, int iterations = 10000)
{
Benchmark<CpuWatch>(action, iterations);
}
}
致电
Clock.BenchmarkTime(() =>
{
//code
}, 10000000);
或
Clock.BenchmarkCpu(() =>
{
//code
}, 10000000);
Clock
的最后一部分是棘手的部分。如果您想显示最终时间,可由您自行选择所需的时间。我写了一个扩展方法NormalizedMean
,它给你读取时间的平均值丢弃噪声。我的意思是我计算每个时间与实际均值的偏差,然后我丢弃从偏差均值(称为绝对偏差;注意它不是经常听到的标准偏差)中得到的值(只有较慢的值),最后返回剩余值的平均值。这意味着,例如,如果定时值为{ 1, 2, 3, 2, 100 }
(以毫秒或其他为单位),则会丢弃100
,并返回{ 1, 2, 3, 2 }
的平均值2
。或者,如果时间安排为{ 240, 220, 200, 220, 220, 270 }
,则会丢弃270
,并返回{ 240, 220, 200, 220, 220 }
的{{1}}的平均值。
220
答案 3 :(得分:13)
使用Stopwatch类
答案 4 :(得分:12)
System.Diagnostics.Stopwatch专为此任务而设计。
答案 5 :(得分:5)
秒表很好,但循环工作10 ^ 6次,然后除以10 ^ 6。 你会得到更多精确度。
答案 6 :(得分:3)
我正在使用它:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(myUrl);
System.Diagnostics.Stopwatch timer = new Stopwatch();
timer.Start();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
statusCode = response.StatusCode.ToString();
response.Close();
timer.Stop();
来自我的博客:C# Time Measurement For Performance Testing(不是英文)
答案 7 :(得分:-12)
是的,Windows内核上有一些功能
[System.Runtime.InteropServices.DllImport("KERNEL32")]
private static extern bool QueryPerformanceCounter(ref long lpPerformanceCount);
[System.Runtime.InteropServices.DllImport("KERNEL32")]
private static extern bool QueryPerformanceFrequency(ref long lpFrequency);
public static float CurrentSecond
{
get
{
long current = 0;
QueryPerformanceCounter(ref current);
long frequency = 0;
QueryPerformanceFrequency(ref frequency);
return (float) current / (float) frequency;
}
}