¿Envolviendo el cronometraje del cronómetro con un delegado o lambda?
Estoy escribiendo código como este, haciendo un poco de sincronización rápida y sucia:
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
b = DoStuff(s);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Seguramente hay una manera de llamar a este poco de código de tiempo como una fantasía-schmancy. NET 3.0 lambda en lugar de (Dios no lo quiera) cortar y pegar un par de veces y reemplazar la DoStuff(s)
con DoSomethingElse(s)
?
Sé que se puede hacer como un Delegate
pero me pregunto acerca de la manera lambda.
9 answers
¿Qué tal extender la clase Cronómetro?
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;
}
}
Entonces llámalo así:
var s = new Stopwatch();
Console.WriteLine(s.Time(() => DoStuff(), 1000));
Podría agregar otra sobrecarga que omita el parámetro "iteraciones" y llama a esta versión con algún valor predeterminado (como 1000).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-25 23:10:53
Esto es lo que he estado usando:
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);
}
}
Uso:
using (new DisposableStopwatch(t => Console.WriteLine("{0} elapsed", t))) {
// do stuff that I want to measure
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-10 20:21:03
Puedes intentar escribir un método de extensión para cualquier clase que estés usando (o cualquier clase base).
Me gustaría que la llamada se vea como:
Stopwatch sw = MyObject.TimedFor(1000, () => DoStuff(s));
Luego el método de extensión:
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;
}
Cualquier objeto derivado de DependencyObject ahora puede llamar a TimedFor(..). La función se puede ajustar fácilmente para proporcionar valores de retorno a través de parámetros ref.
--
Si no desea que la funcionalidad esté vinculada a ninguna clase / objeto, puede hacer algo como:
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;
}
}
Entonces podrías usarlo como:
Stopwatch sw = Timing.TimedFor(() => DoStuff(s), 1000);
En su defecto, esta respuesta parece que tiene alguna habilidad "genérica" decente:
¿Envolviendo el cronometraje del cronómetro con un delegado o lambda?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:04
Escribí una simple clase CodeProfiler hace algún tiempo que envolvía Cronómetro para perfilar fácilmente un método usando una Acción: http://www.improve.dk/blog/2008/04/16/profiling-code-the-easy-way
También le permitirá fácilmente perfilar el código multithreaded. El siguiente ejemplo perfilará la acción lambda con 1-16 hilos:
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();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-18 07:03:40
La clase StopWatch
no necesita ser Disposed
o Stopped
por error. Entonces, el código más simple para time some action es
public partial class With
{
public static long Benchmark(Action action)
{
var stopwatch = Stopwatch.StartNew();
action();
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
}
Ejemplo de código de llamada
public void Execute(Action action)
{
var time = With.Benchmark(action);
log.DebugFormat(“Did action in {0} ms.”, time);
}
No me gusta la idea de incluir las iteraciones en el código StopWatch
. Siempre puede crear otro método o extensión que maneje la ejecución de iteraciones N
.
public partial class With
{
public static void Iterations(int n, Action action)
{
for(int count = 0; count < n; count++)
action();
}
}
Ejemplo de código de llamada
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);
}
Aquí están las versiones del método de extensión
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);
}
}
Y muestra código de llamada
public void Execute(Action action, int n)
{
var time = action.Iterations(n).Benchmark()
log.DebugFormat(“Did action {0} times in {1} ms.”, n, time);
}
Probé los métodos estáticos y los métodos de extensión (combinando iteraciones y benchmark) y el delta del tiempo de ejecución esperado y el tiempo de ejecución real es
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-30 16:44:20
Suponiendo que solo necesita una sincronización rápida de una cosa, esto es fácil de usar.
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; }
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-24 13:27:47
Para mí, la extensión se siente un poco más intuitiva en int, ya no necesita crear una instancia de un cronómetro o preocuparse por restablecerlo.
Así que tienes:
static class BenchmarkExtension {
public static void Times(this int times, string description, Action action) {
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < times; i++) {
action();
}
watch.Stop();
Console.WriteLine("{0} ... Total time: {1}ms ({2} iterations)",
description,
watch.ElapsedMilliseconds,
times);
}
}
Con el uso de la muestra de:
var randomStrings = Enumerable.Range(0, 10000)
.Select(_ => Guid.NewGuid().ToString())
.ToArray();
50.Times("Add 10,000 random strings to a Dictionary",
() => {
var dict = new Dictionary<string, object>();
foreach (var str in randomStrings) {
dict.Add(str, null);
}
});
50.Times("Add 10,000 random strings to a SortedList",
() => {
var list = new SortedList<string, object>();
foreach (var str in randomStrings) {
list.Add(str, null);
}
});
Salida de muestra:
Add 10,000 random strings to a Dictionary ... Total time: 144ms (50 iterations)
Add 10,000 random strings to a SortedList ... Total time: 4088ms (50 iterations)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-12 11:28:15
Puede sobrecargar varios métodos para cubrir varios casos de parámetros que podría querer pasar a la lambda:
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;
}
Alternativamente, puede usar el delegado Func si debe devolver un valor. También puede pasar una matriz (o más) de parámetros si cada iteración debe usar un valor único.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-24 08:55:56
Me gusta usar las clases CodeTimer de Vance Morrison (uno de los tipos de rendimiento de. NET).
Hizo un post en su blog titulado " Midiendo el código administrado de forma rápida y fácil: CodeTimers".
Incluye cosas interesantes como un MultiSampleCodeTimer. Hace el cálculo automático de la media y la desviación estándar y también es muy fácil imprimir sus resultados.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-24 09:48:09