Pregunta ¿La forma más rápida de convertir un objeto a doble?


¿Cuál es la forma más rápida de convertir un objeto en un doble? Estoy en un pedazo de código en este momento, que dice:

var d = double.TryParse(o.ToString(), out d);  // o is the Object...

Los primeros pensamientos fueron reescribir esto como

var d = Convert.ToDouble(o);

pero, ¿sería realmente más rápido?

EDITAR:  Además de ejecutar el perfil (por cierto, lo recomiendo encarecidamente JetBrains dotTrace a cualquier desarrollador), ejecuté Reflector, y eso me ayudó a llegar a lo siguiente (más o menos la parte relevante del código):

if (o is IConvertible)
{
    d = ((IConvertible)o).ToDouble(null);
}
else
{
    d = 0d;
}

El código original double.TryParse() ejecutado en 140ms. El nuevo código se ejecuta en 34 ms. Estoy casi seguro de que esta es la ruta de optimización que debería tomar, pero antes de hacerlo, ¿alguien ve algo problemático con mi código "optimizado"? ¡Gracias de antemano por su colaboración!


10
2017-07-02 16:04


origen


Respuestas:


Debes estar haciendo una gran cantidad de estos para tener algún sentido de dedicar algo de tiempo a esto. Sin embargo, no estoy aquí para juzgar:

Entonces, tu código es este:

if (o is IConvertible)
{
    d = ((IConvertible)o).ToDouble(null);
}
else
{
    d = 0d;
}

Me pregunto si estarías mejor con esto

IConvertible convert = o as IConvertible;

if (convert != null)
{
  d = convert.ToDouble(null);
}
else
{
  d = 0d;
}

Le ahorra el doble molde.


11
2017-07-02 18:11



Probé los siguientes métodos.

  • double.TryParse
  • doble.Parse
  • Convert.ToDouble

Use el siguiente código.

public static void Main()
{
    string text = "3.14";
    var timer = new Stopwatch();
    timer.Start();
    for (int i = 0; i < 10000000; i++)
    {
        double d;
        d = Convert.ToDouble(text);
        //double.TryParse(text, out d);
        //d = double.Parse(text);
    }
    timer.Stop();
    Console.WriteLine("Time=" + timer.Elapsed.ToString());
    Console.ReadLine();
}

En mi máquina, vi estos resultados. Promedí 3 carreras diferentes.

  • double.TryParse = 4.45 segundos
  • double.Parse = 4.45 segundos
  • Convert.ToDouble = 4.75 segundos

Por supuesto, usé una cuerda que era convertible. Si la cadena no es convertible, entonces sospecho mucho double.TryParse será el más rápido por un tiro largo.


5
2017-07-02 16:16



Cree una pequeña aplicación de prueba usando System.Diagnostics.Stopwatch y vea cuál sale más rápido. Aunque yo diría que esto no marcaría una diferencia valiosa. Yo iría por Convert.ToDouble puramente por legibilidad.


3
2017-07-02 16:09



En primer lugar, si realmente desea saber cuál es más rápido, debe escribir una prueba rápida (utilizando los datos que espera procesar) y cronometrar cada opción. Sin saber que o es (o es probable que sea) es muy difícil de juzgar. Sospecho que no vas a ver mucha diferencia.

En segundo lugar, a menos que estés llamando a este fragmento de código en una extremadamente la parte crítica del tiempo de su código, y llamándolo miles de horas para arrancar, dudo que realmente importe. Escribir un buen código, limpio entonces optimizar.


1
2017-07-02 16:10



Hay varias cosas diferentes que podría estar tratando de hacer, dependiendo de qué tipo de cosa es. Podría ser

a) un doble en caja, y solo quieres desempaquetarlo:

object o = 53.2;
double d = (double)o;

b) algún otro tipo, valor o referencia, que tiene alguna conversión a doble disponible (implementa IConvertible.ToDouble ()) que desea usar

object o = 53.2M; // a System.Decimal
double d = Convert.ToDouble(o);

o

c) algo que tiene una representación de cadena predeterminada que se puede analizar como un doble

object o = "53.2";
double d;
bool convertedOK = double.TryParse(o.ToString(), out d);

La opción c es, en cierto sentido, la vuelta más larga; estás tomando tu objeto, pidiendo su representación de cadena, y luego tratando de analizar esa cadena para obtener un doble. Esto es torpe si no necesita hacerlo, y en su ejemplo de 40,000 llamadas va a crear y descartar 40,000 cadenas ...

Si sabe que su objeto siempre contendrá algo que implementa una conversión al doble, puede omitir todo eso y buscar la opción b. Y si sabe que su objeto será un doble en caja, elija la opción más simple (a) para simplemente desempaquetarlo.

Tal vez algo en esta línea te funcione, si realmente no sabes qué será?

double d = (o is double) ? (double)o
    : (o is IConvertible) ? (o as IConvertible).ToDouble(null)
    : double.Parse(o.ToString());

(nota: esto no funcionará si o contiene algo que implementa IConvertible pero no puede convertirse a doble, o si su representación de cadena no puede analizarse como un doble)

No he dicho nada acerca de las velocidades relativas, pero me sorprendería si el desempaquetado no fuera sustancialmente más rápido que la conversión a cadena y luego el análisis (a menos que el optimizador sea lo suficientemente inteligente).

Una prueba rápida en LINQPad usando .NET Stopwatch sugiere una gran diferencia.

IEnumerable<object> myData = new List<object>() { "53.2", 53.2M, 53.2D };
const int iterations = 10000000;
var sw = new Stopwatch();
var results = new List<string>();

foreach (var o in myData)
{
    sw.Reset();
    sw.Start();

    for (var i=0; i < iterations; i++)
    {
        double d = (o is double) ? (double)o
            : (o is IConvertible) ? (o as IConvertible).ToDouble(null)
            : double.Parse(o.ToString());
    }

    sw.Stop();

    results.Add($"{o.GetType()}: {iterations} iterations took {sw.ElapsedMilliseconds}ms");
}

results.Dump();

en mi PC da los siguientes resultados

System.String: 10000000 iterations took 1329ms 
System.Decimal: 10000000 iterations took 402ms 
System.Double: 10000000 iterations took 38ms 

0
2017-12-14 15:55