2009-01-09 9 views
21

Recientemente encontré LINQ y me encanta. Encuentro muchas ocasiones en las que su uso es mucho más expresivo que la versión a mano alzada, pero un colega me hizo un comentario sobre el abuso de esta tecnología que ahora me hace dudar. Desde mi punto de vista, si una tecnología funciona eficientemente y el código es elegante, ¿por qué no usarlo? ¿Es eso incorrecto? Podría pasar más tiempo escribiendo procesos "a mano" y mientras el código resultante puede ser unos pocos ms más rápido, es 2-3 veces más código y, por lo tanto, 2-3 veces más posibilidades de que haya errores.Dónde trazar la línea: ¿es posible amar LINQ demasiado?

¿Mi opinión es incorrecta? ¿Debería escribir mi código a mano en lugar de usar LINQ? ¿No es esto para lo que se diseñó LINQ?

Edit: Estaba hablando de LINQ para objetos, no uso tanto LINQ to XML y he usado LINQ to SQL pero no estoy tan enamorado de esos sabores como LINQ to objects.

+0

no especifica qué sabor .... LINQ to Objects? LINQ a XML? LINQ to SQL? Los dos primeros estoy de acuerdo contigo, el último que no uso. –

Respuesta

19

Tengo que estar de acuerdo con su punto de vista: si es más eficiente escribir y elegante, entonces, ¿qué es unos pocos milisegundos? Escribir código adicional da más espacio para que los errores entren y su código adicional debe ser probado y, sobre todo, es un código extra para mantener. Piensa en el tipo que va a venir detrás de ti y mantener tu código: ¡te agradecerán por escribir un código elegante y fácil de leer mucho antes de que te agradezcan por escribir un código que es unos pocos ms más rápido!

Sin embargo, este costo de algunos ms puede ser significativo cuando se toma en cuenta la imagen más grande. Si esos pocos milisegundos forman parte de un ciclo de miles de repeticiones, los milisegundos se suman rápidamente.

+1

Eso es lo que pensé también. Mi punto de vista es que solo es abuso si se desvive por encontrar razones para usarlo en los lugares equivocados – BobTheBuilder

1

Está respondiendo su propia pregunta hablando de escribir 2-3 veces más código para unos pocos ms de rendimiento. Quiero decir, si su dominio de problema requiere esa aceleración, entonces sí, si no es probable que no. Sin embargo, ¿es realmente solo unos pocos ms de rendimiento o es> 5% o> 10%? Este es un juicio de valor basado en el caso individual.

+0

Supongo que ese es un punto justo: si vas a aumentar cada iteración de un ciclo en unos pocos ms, disminuiría el rendimiento en alguna magnitud; sin embargo, en el caso de los grandes bucles de procesamiento probablemente cifraría el rendimiento antes que la elegancia si significó una diferencia significativa – BobTheBuilder

5

Se supone que LINQ se utiliza para filtrar, ordenar, agregar y manipular datos de diversas fuentes de la forma más intuitiva y expresiva posible. Yo diría que úsala donde sientas que es la sintaxis más ordenada, más expresiva y más natural para hacer lo que estás tratando de hacer, y no te sientas culpable por ello.

Si comienza a recopilar la documentación, puede ser el momento de reconsiderar su posición.

+0

jajaja - sí, si alguna vez empiezo a tener bochornos cuando pienso en programar voy a tomar unas vacaciones: P – BobTheBuilder

+2

¿Entonces la documentación debe estar en la parte superior? – CodeRedick

+1

Creo que la documentación es más como una novia o esposa de un programador. En teoría, siempre debe ser lo primero, pero en realidad se olvida sobre todo hasta que se le recuerda que debe recordarse. – BobTheBuilder

5

casos es todo como estos, donde es importante recordar las reglas de oro de optimización:

  1. no lo hacen
  2. Para los expertos: no lo hacen todavía

Usted debe absolutamente no preocuparse por "abusar" de linq a menos que pueda identificarlo explícitamente como la causa de un problema de rendimiento

+1

No me gusta esto. I Existe una visión razonable que dice algo así como: "No se desvíe prematuramente para optimizar". Sin embargo, esta actitud parece ser más como "haz que sea tan lento como sabes cómo codificarlo rápido". Si uno fuera a tomar esto en serio, uno siempre elegiría el enfoque ingenuo. – BobbyShaftoe

5

Como cualquier cosa, se puede abusar. Mientras se mantenga alejado de las malas decisiones obvias como

var v = List.Where(...); 
for(int i = 0; i < v.Count(); i++) 
{...} 

y entender cómo funciona la ejecución diferida, entonces es muy probable que no va a ser mucho más lento que la forma manuscrita. De acuerdo con Anders Hejlsburg (arquitecto de C#), el compilador de C# no es particularmente bueno en la optimización de bucles, sin embargo, se está volviendo mucho mejor en la optimización y paralelización de árboles de expresiones.Con el tiempo, puede ser más efectivo que un bucle. La versión de ForEach de la lista <> es en realidad tan rápida como un ciclo for, aunque no puedo encontrar el enlace que lo prueba.

P.S. Mi favorito personal es ParaCada <> 's primo menos conocido IndexedForEach (utilizando métodos de extensión)

List.IndexedForEach((p,i) => 
{ 
    if(i != 3) 
     p.DoSomething(i); 
}; 
+0

¿Qué quiere decir con "ejecución diferida"? – BobTheBuilder

+1

Hola Bob, muchas de las declaraciones LINQ en realidad no hacen nada hasta que intentas usarlas. Por ejemplo, List.Where() no se evaluará hasta que se llame a Count(). Sin embargo, el recuento de llamadas evaluará la declaración de cada iteración de bucle, por lo que la instrucción Linq se evalúa cada iteración de bucle – Steve

+0

que conduce a un bajo rendimiento – Steve

8

No es posible amar LINQ a objetos demasiado, es una tecnología increíble volviendo loco!

Pero en serio, cualquier cosa que haga que su código sea simple de leer, fácil de mantener y que haga el trabajo para el que fue diseñado, entonces sería una tontería no usarlo tanto como sea posible.

9

Sí se puede amar demasiado LINQ - Single Statement LINQ RayTracer

¿Dónde se traza la línea? Yo diría que use LINQ tanto como hace que el código sea más simple y fácil de leer.

En el momento en que la versión de LINQ se vuelve más difícil de entender, entonces la versión que no es LINQ es el momento de intercambiar, y viceversa. EDITAR: Esto se aplica principalmente a LINQ-To-Objects ya que los otros sabores LINQ tienen sus propios beneficios.

+0

Dios mío, ese ejemplo de LINQ es ridículo. Debo decir que es poco probable que alguna vez tenga tiempo de descifrar todo eso. Supongo que eso cruza la línea de cordura. – BobTheBuilder

+2

dibujar la línea? Raytracer? Me sale esta broma. –

+0

¡Haha Nicholas, buena persona! Y estoy de acuerdo, es un ejemplo ridículo, pero creo que también es un desafío muy interesante para entender qué y cómo lo hace. –

0

¿Dónde trazar la línea?

Bueno, ya sabemos que es una mala idea implementar su propio quicksort in linq, al menos en comparación con simplemente usar el pedido de linq.

0

He descubierto que el uso de LINQ ha acelerado mi desarrollo y ha hecho que sea más fácil evitar errores estúpidos que los bucles pueden introducir. He tenido instancias en las que el rendimiento de LINQ fue pobre, pero fue cuando lo estaba usando para cosas como buscar datos para un archivo de Excel desde una estructura de árbol que tenía millones de nodos.

0

Aunque veo que hay un punto de vista que LINQ puede hacer que una afirmación sea más difícil de leer, creo que es mucho más importante que mis métodos ahora están estrictamente relacionados con los problemas que están resolviendo y no están gastando tiempo que incluye bucles de búsqueda o clases de desorden con funciones de búsqueda dedicadas.

Me tomó un tiempo acostumbrarme a hacer cosas con LINQ, ya que las búsquedas en bucles, y similares, han sido la opción principal durante tanto tiempo. Considero que LINQ es solo otro tipo de azúcar sintáctico que puede hacer la misma tarea de una manera más elegante. En este momento, todavía lo estoy evitando en el procesamiento, código de misión crítica, pero eso es solo hasta que el rendimiento mejore a medida que LINQ evoluciona.

0

Mi única preocupación sobre LINQ es con su implementación de combinaciones.

Como determiné al intentar responder this question (y está confirmado here), el código que LINQ genera para realizar las uniones es (necesariamente, supongo) ingenuo: para cada elemento de la lista, la unión realiza una búsqueda lineal a través del lista unida para encontrar coincidencias.

Agregar una unión a una consulta LINQ básicamente convierte un algoritmo de tiempo lineal en un algoritmo de tiempo cuadrático. Incluso si piensa que la optimización prematura es la raíz de todo mal, el salto de O (n) a O (n^2) debería darle una pausa. (Es O (n^3) si se une a través de un elemento unido a otra colección, también.)

Es relativamente fácil evitar esto.Por ejemplo, esta consulta:

var list = from pr in parentTable.AsEnumerable() 
join cr in childTable.AsEnumerable() on cr.Field<int>("ParentID") equals pr.Field<int>("ID") 
where pr.Field<string>("Value") == "foo" 
select cr; 

es análogo a cómo uniría dos tablas en SQL Server. Pero es terriblemente ineficiente en LINQ: para cada fila primaria que devuelve la cláusula where, la consulta escanea toda la tabla secundaria. (Incluso si se está uniendo en un campo no indexado, SQL Server va a construir una tabla hash para acelerar la unión si se puede Eso es un poco fuera de nivel de pago de LINQ..)

Esta consulta, sin embargo:

string fk = "FK_ChildTable_ParentTable"; 
var list = from cr in childTable.AsEnumerable() 
where cr.GetParentRow(fk).Field<string>("Value") == "foo" 
select cr; 

produce el mismo resultado, pero escanea la tabla secundaria solo una vez.

Si usa LINQ para objetos, se aplican los mismos problemas: si desea unir dos colecciones de cualquier tamaño significativo, probablemente deba considerar la implementación de un método más eficiente para encontrar el objeto unido, por ejemplo:

Dictionary<Foo, Bar> map = buildMap(foos, bars); 
var list = from Foo f in foos 
where map[f].baz == "bat" 
select f; 
+1

Esto es completamente falso. El operador de unión de LINQ carga todos los elementos en la secuencia interna en una búsqueda eficiente basada en hashtable. Su ejemplo particular es levemente ineficiente en el sentido de que está filtrando DESPUÉS de unirse (en lugar de antes) pero la unión es totalmente eficiente. –

3

LINQ puede ser como el arte. Sigue usándolo para que el código sea hermoso.

Cuestiones relacionadas