Compilación larga de Visual Studio al reemplazar int con double

86

Mi copia de VS2013 Ultimate compila este código durante más de 60 segundos:

class Program
{
    static void Main(string[] args)
    {
        double dichotomy = Dichotomy(
            d =>
            {
                try
                {
                    int size = (int) d;
                    byte[] b = new byte[size];
                    return -b.Length;
                }
                catch (Exception)
                {
                    return 0;
                }
            },
            0,
            int.MaxValue,
            1);

        Console.WriteLine(dichotomy);
        Console.ReadKey();
    }

    private static double Dichotomy(
        Func<double, double> func,
        double a,
        double b,
        double epsilon)
    {
        double delta = epsilon / 10;
        while (b - a >= epsilon)
        {
            double middle = (a + b) / 2;
            double lambda = middle - delta, mu = middle + delta;
            if (func(lambda) < func(mu))
                b = mu;
            else
                a = lambda;
        }
        return (a + b) / 2;
    }
}

Pero si reemplazo doublecon int, se compila inmediatamente. ¿Cómo se explica ...?

Alex Zhukovskiy
fuente
Se compila inmediatamente en mi máquina, para ambos tipos de datos ... ¿En qué máquina lo está compilando?
Chris Mantle
1
Tacha mi primer comentario; Veo el mismo comportamiento. ~ 15 segundos con doublee instantáneo con int. Máquina de 3.4Ghz.
Kevin Richardson
Interesante. Revisé mi versión y en realidad estoy ejecutando VS2013 Premium, pensé que tenía Ultimate instalado. Quizás sea solo la versión Ultimate con la que esto ocurre.
Chris Mantle
1
@chris Solo para respaldar esa hipótesis, VS Express 2013 / Windows Desktop lo compila muy bien.
ClickRick
5
Por lo que he oído, el "comportamiento muy extraño de VS2013" no es una rareza. :)
Lightness Races in Orbit

Respuestas:

140

Repro, 27 segundos en mi máquina. El malhechor es MsMpEng.exe, quema el 100% del núcleo durante ese tiempo. Fácil de ver en la pestaña Procesos del Administrador de tareas.

Este es el servicio de Windows Defender, el que realmente realiza los análisis de malware. Deshabilitarlo desmarcando la opción "Activar protección en tiempo real" corrige instantáneamente el retraso. También lo hace agregar la ruta donde almaceno los proyectos al cuadro "Ubicaciones de archivos excluidos", probablemente su enfoque preferido.

Odiaría tener que adivinar la razón subyacente, pero tengo que asumir que su código fuente está activando una regla de malware. No es una gran explicación, no veo el retraso cuando apunto a una versión .NET <4.0. Está bien, me rindo :)

Hans Passant
fuente
4
Omg, Microsoft, estás bromeando ... Tnx por ayuda, es realmente MSSEy .Net 4.0+quiénes son los culpables
Alex Zhukovskiy
3
¡Buena atrapada! Me pregunto qué causa exactamente el problema (especialmente para un programa que es tan simple y casi no contiene dependencias externas). ¿Sería posible que los bytes de MSIL resultantes de la compilación se vean exactamente como un patrón de un malware conocido y, por lo tanto, se active MsMpEnd?
tigrou
-1

No puedo decirlo con autoridad porque han pasado más de 20 años desde que manipulé el código de ensamblaje, pero puedo creerlo fácilmente.

La diferencia entre las operaciones de punto flotante estándar IEEE y las implementadas por un procesador a menudo obliga a la vinculación en las rutinas de la biblioteca para hacer la traducción, mientras que las matemáticas enteras pueden usar las instrucciones de la CPU. En el momento en que IEEE definió el estándar, tomaron algunas decisiones que eran muy poco comunes en la implementación, y especialmente que hace mucho tiempo eran mucho más caras de implementar en microcódigo y, por supuesto, los sistemas de PC actuales se basan en chips descendientes de 80387 y 80486. , que son anteriores al estándar.

Entonces, si estoy en lo cierto, el aumento de tiempo se debe a que implica agregar una parte del código de la biblioteca al enlace, y la vinculación es una gran parte del tiempo de compilación que tiende a crecer multiplicativamente a medida que se agregan partes reubicables.

Clang en Linux puede tener o no la misma ralentización; si lo evita, y extendiendo mis conjeturas aún más, eso sería un artefacto de la omnipresente libc de memoria compartida que se obtiene y las optimizaciones del enlazador en torno a eso.

jugador
fuente