45 votes

Les conversions redondantes sont-elles optimisées?

Je suis à jour certains de l'ancien code, et ont relevé plusieurs cas où le même objet est jeté à plusieurs reprises chaque fois que l'une de ses propriétés ou des méthodes doit être appelé. Exemple:

if (recDate != null && recDate > ((System.Windows.Forms.DateTimePicker)ctrl).MinDate)
{
    ((System.Windows.Forms.DateTimePicker)ctrl).CustomFormat = "MM/dd/yyyy";
    ((System.Windows.Forms.DateTimePicker)ctrl).Value = recDate;
}
else
{
    (System.Windows.Forms.DateTimePicker)ctrl).CustomFormat = " ";
}
((System.Windows.Forms.DateTimePicker)ctrl).Format = DateTimePickerFormat.Custom;

Mon envie est de fixer cette monstruosité, mais étant donné mon peu de temps, je ne voulez pas vous embêter avec tout ce qui n'affectent pas la fonctionnalité ou à la performance.

Donc ce que je me pose est, est-il redondant jette arriver optimisé par le compilateur? J'ai essayé de trouver moi-même en utilisant ildasm sur un exemple simplifié, mais n'étant pas familier avec IL je ne fini plus confus.

Mise à JOUR

Jusqu'à présent, le consensus semble être que non, ces distributions ne sont pas optimisé, mais b)alors qu'il y a peut-être quelques petites performances en conséquence, il n'est probablement pas significative, et c)que je devrais envisager de fixation de toute façon. Je suis descendu sur le côté de la résolution de corriger un jour, si j'ai le temps. Pendant ce temps, je ne vais pas vous en soucier.

Merci à tous!

21voto

Hans Passant Points 475940

Un contrôle sur place sur le code machine dans la Version de publication montre que le x86 gigue n'est pas d'optimiser le jette.

Vous avez à regarder la grande image ici. Vous êtes l'attribution de propriétés d'un contrôle. Ils ont une tonne d'effets secondaires. Dans le cas de DateTimePicker, l'affectation des résultats dans un message envoyé à l'natif de contrôle de Windows. Qui craque de suite le message. Le coût de la distribution est négligeable pour le coût des effets secondaires. Réécrire les affectations ne va jamais à faire une différence notable dans la vitesse, vous fait seulement une fraction de un pour cent plus rapide.

Aller de l'avant et faire réécrire le code sur un paresseux vendredi après-midi. Mais seulement parce qu'il est un fléau pour des raisons de lisibilité. Que mal lisible le code C# produit aussi mal optimisé le code machine n'est pas totalement un hasard.

19voto

Nathan Ernst Points 3079

Il n'est pas optimisé loin de IL en soit debug ou release.

simple C# test:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RedundantCastTest
{
    class Program
    {
        static object get()
        { return "asdf"; }

        static void Main(string[] args)
        {
            object obj = get();
            if ((string)obj == "asdf")
                Console.WriteLine("Equal: {0}, len: {1}", obj, ((string)obj).Length);
        }
    }
}

Correspondant de l'IL (note multiples castclass instructions):

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 3
    .locals init (
        [0] object obj,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: call object RedundantCastTest.Program::get()
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: castclass string
    L_000d: ldstr "asdf"
    L_0012: call bool [mscorlib]System.String::op_Equality(string, string)
    L_0017: ldc.i4.0 
    L_0018: ceq 
    L_001a: stloc.1 
    L_001b: ldloc.1 
    L_001c: brtrue.s L_003a
    L_001e: ldstr "Equal: {0}, len: {1}"
    L_0023: ldloc.0 
    L_0024: ldloc.0 
    L_0025: castclass string
    L_002a: callvirt instance int32 [mscorlib]System.String::get_Length()
    L_002f: box int32
    L_0034: call void [mscorlib]System.Console::WriteLine(string, object, object)
    L_0039: nop 
    L_003a: ret 
}

Ni est-il optimisé de la IL en de la version de publication:

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 3
    .locals init (
        [0] object obj)
    L_0000: call object RedundantCastTest.Program::get()
    L_0005: stloc.0 
    L_0006: ldloc.0 
    L_0007: castclass string
    L_000c: ldstr "asdf"
    L_0011: call bool [mscorlib]System.String::op_Equality(string, string)
    L_0016: brfalse.s L_0033
    L_0018: ldstr "Equal: {0}, len: {1}"
    L_001d: ldloc.0 
    L_001e: ldloc.0 
    L_001f: castclass string
    L_0024: callvirt instance int32 [mscorlib]System.String::get_Length()
    L_0029: box int32
    L_002e: call void [mscorlib]System.Console::WriteLine(string, object, object)
    L_0033: ret 
}

Aucun des cas signifie que les jette n'obtenez pas optimisé lorsque le code natif est généré - vous devez regarder la machine réelle de l'assemblée. c'est à dire en exécutant ngen et le démontage. Je serais très surpris si ce n'était pas du tout optimisé loin.

Peu importe, je vais citer La Pragmatique Programmeur et la fenêtre cassée théorème: Quand vous voyez une fenêtre cassée, le réparer.

6voto

Mark Sowul Points 4249

Non; FxCop le signale comme un avertissement de performance. Voir les informations ici: http://msdn.microsoft.com/en-us/library/ms182271.aspx

Je vous recommande d'exécuter cette opération sur votre code si vous souhaitez trouver des solutions à votre problème.

1voto

Bob Points 34449

Je n'ai jamais entendu parler ni vu d'optimisations redondantes de la distribution sur le CLR. Essayons un exemple artificiel

 object number = 5;
int iterations = 10000000;
int[] storage = new int[iterations];

var sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++) {
    storage[i] = ((int)number) + 1;
    storage[i] = ((int)number) + 2;
    storage[i] = ((int)number) + 3;
}
Console.WriteLine(sw.ElapsedTicks);

storage = new int[iterations];

sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++) {
    var j = (int)number;
    storage[i] = j + 1;
    storage[i] = j + 2;
    storage[i] = j + 3;
}
Console.WriteLine(sw.ElapsedTicks);
Console.ReadLine();
 

Sur ma machine, en cours de lancement, je reçois régulièrement environ 350 000 ticks pour la redondance redondante et 280 000 ticks pour l’optimisation de soi. Donc non, il semble que le CLR ne soit pas optimisé pour cela.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X