Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

302
Visualizações
Comparación redundante y "si" antes de la asignación

Aquí está el ejemplo:

 if(value != ageValue) { ageValue = value; }

Es decir, si asignamos el valor de una variable a otra, ¿por qué tendríamos que verificar si tienen el mismo valor de todos modos?

Eso me confunde. Aquí está el contexto más amplio:

 private double ageValue; public double Age { get { return ageValue; } set { if(value != ageValue) { ageValue = value; } } }
over 4 years ago · Santiago Trujillo
7 Respostas
Responde à pergunta

0

Sí, esto if es inútil. Comprueba si el valor es el mismo (y configúralo si no).

Cuando el operador != no está sobrecargado, entonces es esto:

 private double ageValue; public double Age { get { return ageValue; } set { if (value != ageValue) { ageValue = value; } } }

Lo mismo

 private double ageValue; public double Age { get { return ageValue; } set { ageValue = value; } }
over 4 years ago · Santiago Trujillo Relatório

0

El if es, en la inspección, no redundante. Depende de la implementación restante. Tenga en cuenta que en C#, != se puede sobrecargar, lo que significa que la evaluación puede tener efectos secundarios. Además, las variables marcadas podrían implementarse como propiedades, lo que también puede tener efectos secundarios en la evaluación.

over 4 years ago · Santiago Trujillo Relatório

0

En un control de winforms habíamos establecido el Color de fondo en un color específico:

 myControl.BackgroundColor = Color.White

En circunstancias específicas, esto podría ocurrir en un bucle cerrado y conducir a una interfaz de usuario congelada. Después de un análisis de rendimiento, descubrimos que esta llamada era el motivo de la IU congelada, por lo que simplemente la cambiamos a:

 if (myControl.BackgroundColor != Color.White) myControl.BackgroundColor = Color.White

Y el rendimiento de nuestra herramienta volvió a la normalidad (y luego eliminamos la razón del ciclo cerrado).

Así que esta verificación no siempre es redundante. Especialmente si el objetivo es una propiedad que hace más dentro del setter que simplemente aplicar el valor a una tienda de respaldo.

over 4 years ago · Santiago Trujillo Relatório

0

Aquí hay una muestra de código cuando la verificación es bastante útil :

 public class MyClass { ... int ageValue = 0; public int AgeValue { get { return ageValue } protected set { ... // value validation here // your code starts if (value != ageValue) { ageValue = value; } // your code ends else return; // do nothing since value == ageValue // ageValue has been changed // Time (or / and memory) consuming process SaveToRDBMS(); InvalidateCache(); ... } } ...

Sin embargo, una implementación más natural es verificar desde el principio para evitar cálculos innecesarios.

 protected set { if (ageValue == value) return; ... // value validation here ageValue = value; // ageValue has been changed // Time (or / and memory) consuming process SaveToRDBMS(); InvalidateCache(); ... }
over 4 years ago · Santiago Trujillo Relatório

0

Esta pregunta ha ganado bastantes comentarios, pero hasta ahora todas las respuestas intentan reformular la pregunta para abordar problemas con la sobrecarga del operador o los efectos secundarios del colocador.

Si el setter es utilizado por varios subprocesos, realmente puede marcar la diferencia. El patrón de verificación antes de establecer puede (debe medir) ser útil si está iterando sobre los mismos datos con múltiples hilos que alteran los datos. El nombre de libro de texto para este fenómeno se llama intercambio falso . Si leyó los datos y verificó que ya coincide con el valor objetivo, puede omitir la escritura.

Si omite la escritura, la CPU no necesita vaciar la línea de caché (un bloque de 64 bytes en las CPU Intel) para asegurarse de que otros núcleos vean el valor modificado. Si el otro núcleo estaba a punto de leer otros datos de ese bloque de 64 bytes, simplemente ha ralentizado su núcleo y ha aumentado el tráfico entre núcleos para sincronizar el contenido de la memoria entre las memorias caché de la CPU.

La siguiente aplicación de ejemplo muestra este efecto que también contiene la condición de verificación antes de escribir:

 if (tmp1 != checkValue) // set only if not equal to checkvalue { values[i] = checkValue; }

Aquí está el código completo:

 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; class Program { static void Main(string[] args) { const int N = 500_000_000; int[] values = new int[N]; // 2 GB for (int nThreads = 1; nThreads < Environment.ProcessorCount; nThreads++) { SetArray(values, checkValue: 1, nTimes: 10, nThreads: nThreads); SetArray(values, checkValue: 2, nTimes: 10, nThreads: nThreads); SetArrayNoCheck(values, checkValue: 2, nTimes: 10, nThreads: nThreads); } } private static void SetArray(int[] values, int checkValue, int nTimes, int nThreads) { List<double> ms = new List<double>(); for (int k = 0; k < nTimes; k++) // set array values to 1 { for (int i = 0; i < values.Length; i++) { values[i] = 1; } var sw = Stopwatch.StartNew(); Action acc = () => { int tmp1 = 0; for (int i = 0; i < values.Length; i++) { tmp1 = values[i]; if (tmp1 != checkValue) // set only if not equal to checkvalue { values[i] = checkValue; } } }; Parallel.Invoke(Enumerable.Repeat(acc, nThreads).ToArray()); // Let this run on 3 cores sw.Stop(); ms.Add(sw.Elapsed.TotalMilliseconds); // Console.WriteLine($"Set {values.Length * 4 / (1_000_000_000.0f):F1} GB of Memory in {sw.Elapsed.TotalMilliseconds:F0} ms. Initial Value 1. Set Value {checkValue}"); } string descr = checkValue == 1 ? "Conditional Not Set" : "Conditional Set"; Console.WriteLine($"{descr}, {ms.Average():F0}, ms, nThreads, {nThreads}"); } private static void SetArrayNoCheck(int[] values, int checkValue, int nTimes, int nThreads) { List<double> ms = new List<double>(); for (int k = 0; k < nTimes; k++) // set array values to 1 { for (int i = 0; i < values.Length; i++) { values[i] = 1; } var sw = Stopwatch.StartNew(); Action acc = () => { for (int i = 0; i < values.Length; i++) { values[i] = checkValue; } }; Parallel.Invoke(Enumerable.Repeat(acc, nThreads).ToArray()); // Let this run on 3 cores sw.Stop(); ms.Add(sw.Elapsed.TotalMilliseconds); //Console.WriteLine($"Unconditional Set {values.Length * 4 / (1_000_000_000.0f):F1} GB of Memory in {sw.Elapsed.TotalMilliseconds:F0} ms. Initial Value 1. Set Value {checkValue}"); } Console.WriteLine($"Unconditional Set, {ms.Average():F0}, ms, nThreads, {nThreads}"); } }

Si dejas que se ejecute, obtienes valores como:

 // Value not set Set 2.0 GB of Memory in 439 ms. Initial Value 1. Set Value 1 Set 2.0 GB of Memory in 420 ms. Initial Value 1. Set Value 1 Set 2.0 GB of Memory in 429 ms. Initial Value 1. Set Value 1 Set 2.0 GB of Memory in 393 ms. Initial Value 1. Set Value 1 Set 2.0 GB of Memory in 404 ms. Initial Value 1. Set Value 1 Set 2.0 GB of Memory in 395 ms. Initial Value 1. Set Value 1 Set 2.0 GB of Memory in 419 ms. Initial Value 1. Set Value 1 Set 2.0 GB of Memory in 421 ms. Initial Value 1. Set Value 1 Set 2.0 GB of Memory in 442 ms. Initial Value 1. Set Value 1 Set 2.0 GB of Memory in 422 ms. Initial Value 1. Set Value 1 // Value written Set 2.0 GB of Memory in 519 ms. Initial Value 1. Set Value 2 Set 2.0 GB of Memory in 582 ms. Initial Value 1. Set Value 2 Set 2.0 GB of Memory in 543 ms. Initial Value 1. Set Value 2 Set 2.0 GB of Memory in 484 ms. Initial Value 1. Set Value 2 Set 2.0 GB of Memory in 523 ms. Initial Value 1. Set Value 2 Set 2.0 GB of Memory in 540 ms. Initial Value 1. Set Value 2 Set 2.0 GB of Memory in 552 ms. Initial Value 1. Set Value 2 Set 2.0 GB of Memory in 527 ms. Initial Value 1. Set Value 2 Set 2.0 GB of Memory in 535 ms. Initial Value 1. Set Value 2 Set 2.0 GB of Memory in 581 ms. Initial Value 1. Set Value 2

Eso da como resultado un rendimiento un 22% más rápido que puede ser significativo en escenarios de procesamiento de números de alto rendimiento.

Para responder a la pregunta como estaba escrito:

Puede eliminar la declaración if si el acceso a la memoria es solo de un solo subproceso. Si varios subprocesos están trabajando en los mismos datos o en datos cercanos, puede ocurrir un intercambio falso que puede costarle hasta aprox. 20% del rendimiento de acceso a la memoria.

Actualización 1 Realicé más pruebas y creé un gráfico para mostrar el chat de chit de núcleo cruzado. Esto muestra un conjunto simple (conjunto incondicional ) como lo señaló el comentarista Frank Hopkins. Conditional Not Set contiene el if que nunca establece el valor. Y por último, pero no menos importante, el conjunto condicional establecerá el valor en la condición if.

Rendimiento frente a núcleos

over 4 years ago · Santiago Trujillo Relatório

0

De hecho, he codificado cosas como esta varias veces, por diferentes razones. Son un poco difíciles de explicar, así que tengan paciencia conmigo.

Lo principal es que no establece una nueva referencia si el valor en la referencia es lógicamente igual al valor de la referencia anterior. En los comentarios anteriores, los usuarios han criticado lo detestable de este escenario, y es detestable tener que lidiar con él, pero sigue siendo esencialmente necesario en los casos.

Intentaría dividir casos de uso como este:

  1. El valor es un tipo de datos abstracto, donde puede tener diferentes instancias construidas que representan el mismo valor lógico.

    • Esto sucede mucho en los programas matemáticos, por ejemplo, Mathematica, donde no puede usar números primitivos, lo que le permite terminar con diferentes objetos destinados a representar lo mismo.
  2. La referencia de value es útil para una lógica de almacenamiento en caché.

    • Esto también puede aparecer cuando se usan números abstractos. Por ejemplo, si espera que otras partes del programa tengan datos almacenados en caché sobre una referencia, entonces no desea reemplazarlo con una referencia lógicamente equivalente, ya que invalidará los cachés utilizados en otros lugares.
  3. Está utilizando un evaluador reactivo, donde establecer un nuevo valor puede forzar una reacción en cadena de actualizaciones.

    • Exactamente cómo y por qué esto es importante varía según el contexto.

El gran punto conceptual es que, en algunos casos, puede tener el mismo valor lógico almacenado en diferentes referencias, pero desea intentar minimizar la cantidad de referencias degeneradas por dos grandes razones:

  1. Tener el mismo valor lógico almacenado varias veces consume más memoria.

  2. Gran parte del tiempo de ejecución puede usar la verificación de referencias como un atajo, por ejemplo, a través del almacenamiento en caché, que puede ser más eficiente si evita permitir que se propaguen referencias redundantes al mismo valor lógico.

Para otro ejemplo aleatorio, el recolector de basura de .NET es " generacional " , lo que significa que se esfuerza más en verificar si se puede recopilar un valor cuando es más nuevo. Por lo tanto, el recolector de elementos no utilizados puede experimentar ganancias si prefiere conservar la referencia anterior, ya que se encuentra en una generación más privilegiada, lo que permite que la referencia más nueva recolecte elementos no utilizados antes.

Otro caso de uso, de nuevo con tipos de datos abstractos, es donde puede tener propiedades evaluadas de forma perezosa adjuntas a ellos. Por ejemplo, supongamos que tiene un abstract class Number que tiene propiedades como .IsRational , .IsEven , etc. Entonces, es posible que no los calcule de inmediato, sino que los genere a pedido, almacenando en caché los resultados. En un escenario como este, es posible que prefiera conservar los Number anteriores del mismo valor lógico, ya que pueden tener más cosas adjuntas, mientras que un value nuevo puede tener menos información asociada, incluso si es lógicamente == .

Es un poco difícil pensar en cómo resumir las diversas razones por las que esto puede tener sentido en algunos casos, pero básicamente es una optimización que puede tener sentido si tiene una razón para usarla. Si no tiene ninguna razón para usarlo, probablemente sea mejor no preocuparse hasta que surja alguna motivación.

over 4 years ago · Santiago Trujillo Relatório

0

El rendimiento no es un gran problema, solo depende de sus necesidades lógicas.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda