son compiladores como Javac lo suficientemente inteligentes como para detectar cuándo un método es una función pura.
No es una cuestión de "suficientemente inteligente". Esto se denomina Análisis de pureza y es demostrablemente imposible en el caso general: es equivalente a resolver el problema de detención.
Ahora, por supuesto, los optimizadores hacen cosas probablemente imposibles todo el tiempo, "probablemente imposible en el caso general" no significa que nunca funcione, solo significa que no puede funcionar en todos los casos. Entonces, de hecho, hay algoritmos para verificar si una función es pura o no, es solo que la mayoría de las veces el resultado será "No sé", lo que significa que, por razones de seguridad y corrección, debe asumir que esta función en particular podría ser impura.
E incluso en los casos en que funciona , los algoritmos son complejos y caros.
Entonces, eso es Problema # 1: solo funciona en casos especiales .
Problema nº 2: Bibliotecas . Para que una función sea pura, solo puede llamar funciones puras (y esas funciones solo pueden llamar funciones puras, y así sucesivamente). Javac, obviamente, solo conoce Java, y solo conoce el código que puede ver. Por lo tanto, si su función llama a una función en otra unidad de compilación, no puede saber si es pura o no. Si llama a una función escrita en otro idioma, no puede saberlo. Si llama a una función de una biblioteca que aún no está instalada, no puede saberlo. Y así sucesivamente.
Esto solo funciona, cuando se tiene un análisis de todo el programa, cuando todo el programa está escrito en el mismo idioma y todo se compila de una en una. No puedes usar ninguna biblioteca.
Problema nº 3: Programación . Una vez que haya descubierto qué partes son puras, todavía tiene que programarlas para separar hilos. O no. Iniciar y detener subprocesos es muy costoso (especialmente en Java). Incluso si mantiene un grupo de subprocesos y no los inicia ni los detiene, el cambio de contexto de subprocesos también es costoso. Debe asegurarse de que el cálculo se ejecute significativamente más tiempo que el tiempo necesario para programar y cambiar el contexto, de lo contrario, perderá el rendimiento, no lo ganará.
Como probablemente ya haya adivinado, calcular el tiempo que demorará un cálculo es probablemente imposible en el caso general (ni siquiera podemos determinar si tomará una cantidad de tiempo finita, por no hablar de cuánto tiempo) y difícil y caro incluso en el caso especial.
Aparte: Javac y optimizaciones . Tenga en cuenta que la mayoría de las implementaciones de javac no realizan muchas optimizaciones. La implementación de Oracle de javac, por ejemplo, se basa en el motor de ejecución subyacente para realizar optimizaciones . Esto conduce a otro conjunto de problemas: digamos, javac decidió que una función en particular es pura y bastante costosa, y por eso la compila para que se ejecute en un hilo diferente. Luego, aparece el optimizador de la plataforma (por ejemplo, el compilador JS HotSpot C2) y optimiza toda la función. Ahora, tienes un hilo vacío que no hace nada. O, imagina, otra vez, javac decide programar una función en un subproceso diferente, y el optimizador de plataforma podría optimizarlo completamente, excepto que no puede realizar la alineación a través de los límites de los subprocesos, y por lo tanto una función que podría ser optimizado completamente se ejecuta ahora innecesariamente.
Por lo tanto, hacer algo como esto solo tiene sentido si tiene un solo compilador que realiza la mayoría de las optimizaciones de una sola vez, para que el compilador conozca y pueda explotar todas las diferentes optimizaciones en diferentes niveles y sus interacciones entre sí. .
Tenga en cuenta que, por ejemplo, el compilador JIT HotSpot C2 en realidad hace realiza cierta auto-vectorización, que también es una forma de auto-paralelización.