[c#] 델리게이트 또는 람다로 스톱워치 타이밍을 래핑 하시겠습니까?
나는 약간 빠르고 더러운 타이밍을 사용하여 이와 같은 코드를 작성하고 있습니다.
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
b = DoStuff(s);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
확실히이 타이밍 코드를 몇 번 자르고 붙여넣고 DoStuff(s)
를 DoSomethingElse(s)
?
나는 그것이 할 수 있다는 것을 알고 Delegate
있지만 람다 방식에 대해 궁금합니다.
답변
스톱워치 클래스를 확장하는 것은 어떻습니까?
public static class StopwatchExtensions
{
public static long Time(this Stopwatch sw, Action action, int iterations)
{
sw.Reset();
sw.Start();
for (int i = 0; i < iterations; i++)
{
action();
}
sw.Stop();
return sw.ElapsedMilliseconds;
}
}
그런 다음 다음과 같이 호출하십시오.
var s = new Stopwatch();
Console.WriteLine(s.Time(() => DoStuff(), 1000));
“iterations”매개 변수를 생략하고 일부 기본값 (예 : 1000)으로이 버전을 호출하는 또 다른 오버로드를 추가 할 수 있습니다.
답변
내가 사용한 것은 다음과 같습니다.
public class DisposableStopwatch: IDisposable {
private readonly Stopwatch sw;
private readonly Action<TimeSpan> f;
public DisposableStopwatch(Action<TimeSpan> f) {
this.f = f;
sw = Stopwatch.StartNew();
}
public void Dispose() {
sw.Stop();
f(sw.Elapsed);
}
}
용법:
using (new DisposableStopwatch(t => Console.WriteLine("{0} elapsed", t))) {
// do stuff that I want to measure
}
답변
사용중인 클래스 (또는 기본 클래스)에 대해 확장 메서드를 작성해 볼 수 있습니다.
전화는 다음과 같습니다.
Stopwatch sw = MyObject.TimedFor(1000, () => DoStuff(s));
그런 다음 확장 방법 :
public static Stopwatch TimedFor(this DependencyObject source, Int32 loops, Action action)
{
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < loops; ++i)
{
action.Invoke();
}
sw.Stop();
return sw;
}
DependencyObject에서 파생 된 모든 개체는 이제 TimedFor (..)를 호출 할 수 있습니다. 함수는 ref 매개 변수를 통해 반환 값을 제공하도록 쉽게 조정할 수 있습니다.
–
기능이 클래스 / 객체에 연결되는 것을 원하지 않는 경우 다음과 같이 할 수 있습니다.
public class Timing
{
public static Stopwatch TimedFor(Action action, Int32 loops)
{
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < loops; ++i)
{
action.Invoke();
}
sw.Stop();
return sw;
}
}
그런 다음 다음과 같이 사용할 수 있습니다.
Stopwatch sw = Timing.TimedFor(() => DoStuff(s), 1000);
실패하면이 답변은 괜찮은 “일반적인”능력을 가지고있는 것처럼 보입니다.
답변
StopWatch
클래스 일 필요는 없습니다 Disposed
또는 Stopped
오류에. 그래서, 간단한 코드에 시간이 몇 가지 조치가 있다
public partial class With
{
public static long Benchmark(Action action)
{
var stopwatch = Stopwatch.StartNew();
action();
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
}
샘플 호출 코드
public void Execute(Action action)
{
var time = With.Benchmark(action);
log.DebugFormat(“Did action in {0} ms.”, time);
}
StopWatch
코드에 반복을 포함하는 아이디어가 마음에 들지 않습니다 . N
반복 실행을 처리하는 다른 메서드 또는 확장을 언제든지 만들 수 있습니다 .
public partial class With
{
public static void Iterations(int n, Action action)
{
for(int count = 0; count < n; count++)
action();
}
}
샘플 호출 코드
public void Execute(Action action, int n)
{
var time = With.Benchmark(With.Iterations(n, action));
log.DebugFormat(“Did action {0} times in {1} ms.”, n, time);
}
다음은 확장 메서드 버전입니다.
public static class Extensions
{
public static long Benchmark(this Action action)
{
return With.Benchmark(action);
}
public static Action Iterations(this Action action, int n)
{
return () => With.Iterations(n, action);
}
}
그리고 샘플 호출 코드
public void Execute(Action action, int n)
{
var time = action.Iterations(n).Benchmark()
log.DebugFormat(“Did action {0} times in {1} ms.”, n, time);
}
정적 메서드와 확장 메서드 (반복 및 벤치 마크 결합)를 테스트했으며 예상 실행 시간과 실제 실행 시간의 델타는 <= 1ms입니다.
답변
Action을 사용하여 메서드를 쉽게 프로파일 링하기 위해 Stopwatch를 래핑 한 간단한 CodeProfiler 클래스를 얼마 전에 작성했습니다.
http://www.improve.dk/blog/2008/04/16/profiling-code-the-easy-way
또한 다중 스레드 코드를 쉽게 프로파일 링 할 수 있습니다. 다음 예제는 1-16 개의 스레드로 작업 람다를 프로파일 링합니다.
static void Main(string[] args)
{
Action action = () =>
{
for (int i = 0; i < 10000000; i++)
Math.Sqrt(i);
};
for(int i=1; i<=16; i++)
Console.WriteLine(i + " thread(s):\t" +
CodeProfiler.ProfileAction(action, 100, i));
Console.Read();
}
답변
한 가지 빠른 타이밍이 필요하다고 가정하면 사용하기 쉽습니다.
public static class Test {
public static void Invoke() {
using( SingleTimer.Start )
Thread.Sleep( 200 );
Console.WriteLine( SingleTimer.Elapsed );
using( SingleTimer.Start ) {
Thread.Sleep( 300 );
}
Console.WriteLine( SingleTimer.Elapsed );
}
}
public class SingleTimer :IDisposable {
private Stopwatch stopwatch = new Stopwatch();
public static readonly SingleTimer timer = new SingleTimer();
public static SingleTimer Start {
get {
timer.stopwatch.Reset();
timer.stopwatch.Start();
return timer;
}
}
public void Stop() {
stopwatch.Stop();
}
public void Dispose() {
stopwatch.Stop();
}
public static TimeSpan Elapsed {
get { return timer.stopwatch.Elapsed; }
}
}
답변
여러 메서드를 오버로드하여 람다에 전달할 수있는 다양한 매개 변수 사례를 처리 할 수 있습니다.
public static Stopwatch MeasureTime<T>(int iterations, Action<T> action, T param)
{
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < iterations; i++)
{
action.Invoke(param);
}
sw.Stop();
return sw;
}
public static Stopwatch MeasureTime<T, K>(int iterations, Action<T, K> action, T param1, K param2)
{
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < iterations; i++)
{
action.Invoke(param1, param2);
}
sw.Stop();
return sw;
}
또는 값을 반환해야하는 경우 Func 대리자를 사용할 수 있습니다. 각 반복이 고유 한 값을 사용해야하는 경우 매개 변수의 배열 (또는 그 이상)을 전달할 수도 있습니다.