¿Los compiladores como Javac detectan automáticamente las funciones puras y las ponen en paralelo?

12

Se sabe que las funciones puras facilitan la parellelización. ¿Qué es ¿Se trata de una programación funcional que la hace inherentemente adaptada a la ejecución paralela?

¿Son los compiladores como Javac lo suficientemente inteligentes como para detectar cuándo un método es una función pura? Siempre se pueden implementar clases que implementen interfaces funcionales como Function ,  pero tienen efectos secundarios.

    
pregunta Naveen 09.07.2017 - 09:06

2 respuestas

33
  

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.

    
respondido por el Jörg W Mittag 09.07.2017 - 11:31
5

La respuesta upvota no pudo notar una cosa. La comunicación síncrona entre hilos es extremadamente costosa. Si la función es capaz de ejecutarse a una velocidad de muchos millones de llamadas por segundo, realmente le duele más paralelizarla en lugar de dejarla como está.

La forma más rápida de comunicación entre subprocesos síncrona, utilizando bucles ocupados con variables atómicas, desafortunadamente es ineficiente en cuanto a energía. Si tiene que recurrir al uso de variables de condición para ahorrar energía, el rendimiento de su comunicación entre subprocesos sufre.

Por lo tanto, el compilador no solo necesita determinar si una función es pura, sino que también debería estimar el tiempo de ejecución de la función para ver si la paralelización es una ganancia neta. Además, tendría que elegir entre bucles ocupados utilizando variables atómicas o variables de condición. Y tendría que crear hilos detrás de tu espalda.

Si crea los subprocesos dinámicamente, es incluso más lento que usar variables de condición. Por lo tanto, el compilador deberá configurar un cierto número de subprocesos que ya se estén ejecutando.

Entonces, la respuesta a su pregunta es no , los compiladores no son lo suficientemente "inteligentes" para auto-paralelizar funciones puras, especialmente en el mundo Java. ¡Son inteligentes al no paralelizarlos automáticamente!

    
respondido por el juhist 09.07.2017 - 14:29

Lea otras preguntas en las etiquetas