sono compilatori come Javac abbastanza intelligenti da rilevare quando un metodo è una funzione pura.
Non è una questione di "abbastanza intelligente". Questo si chiama Analisi della Purezza ed è dimostrabilmente impossibile nel caso generale: equivale a risolvere il problema dell'arresto.
Ora, naturalmente, gli ottimizzatori fanno continuamente cose impossibili, "dimostrabilmente impossibili nel caso generale" non significa che non funzioni mai, significa solo che non possono funzionare in tutti i casi. Quindi, ci sono infatti algoritmi per verificare se una funzione è pura o no, è solo che il più delle volte il risultato sarà "Non lo so", il che significa che per motivi di sicurezza e correttezza, devi assumere che questa particolare funzione potrebbe essere impura.
E anche nei casi in cui si fa il lavoro, gli algoritmi sono complessi e costosi.
Quindi, questo è il problema n. 1: funziona solo per casi speciali .
Problema n. 2: librerie . Affinché una funzione sia pura, può sempre e solo chiamare funzioni pure (e quelle funzioni possono solo chiamare funzioni pure, e così via e così via). Javac ovviamente conosce solo Java e conosce solo il codice che può vedere. Quindi, se la tua funzione chiama una funzione in un'altra unità di compilazione, non puoi sapere se è pura o no. Se chiama una funzione scritta in un'altra lingua, non puoi saperlo. Se chiama una funzione in una libreria che potrebbe non essere ancora installata, non puoi saperlo. E così via.
Funziona solo quando si ha l'analisi dell'intero programma, quando l'intero programma è scritto nella stessa lingua e tutto viene compilato in una volta sola. Non puoi usare nessuna biblioteca.
Problema n. 3: programmazione . Una volta che hai capito quali parti sono pure, devi ancora programmarle per separare i thread. O no. L'avvio e l'arresto dei thread è molto costoso (specialmente in Java). Anche se si mantiene un pool di thread e non si avvia o si interrompe, anche il cambio di contesto del thread è costoso. È necessario essere sicuri che il calcolo verrà eseguito in modo significativamente più lungo del tempo necessario per la pianificazione e il cambio di contesto, altrimenti si perderanno prestazioni, non si ottiene.
Come probabilmente hai già indovinato, capire quanto tempo impiegherà un calcolo è dimostrabilmente impossibile nel caso generale (non possiamo nemmeno capire se ci vorrà un tempo finito, figuriamoci quanto tempo) e difficile e costoso anche in il caso speciale.
A parte: Javac e ottimizzazioni . Nota che la maggior parte delle implementazioni di javac in realtà non esegue molte ottimizzazioni. L'implementazione di Oracle di javac, ad esempio, si basa sul motore di esecuzione sottostante per eseguire ottimizzazioni . Questo porta ad un altro insieme di problemi: diciamo, javac ha deciso che una particolare funzione è pura ed è abbastanza costosa, e quindi la compila per essere eseguita su un thread diverso. Quindi, arriva l'ottimizzatore della piattaforma (ad esempio, il compilatore JIT HotSpot C2) e ottimizza l'intera funzione. Ora, hai un thread vuoto che non fa nulla. Oppure, immagina, ancora una volta, javac decide di pianificare una funzione su un thread diverso e l'ottimizzatore della piattaforma potrebbe farlo ottimizzarlo completamente, tranne per il fatto che non può eseguire l'allineamento oltre i limiti del thread, quindi una funzione che potrebbe essere ottimizzata completamente è ora inutilmente eseguita.
Quindi, fare una cosa del genere ha senso solo se si dispone di un singolo compilatore che fa la maggior parte delle ottimizzazioni in una volta sola, in modo che il compilatore sia a conoscenza e possa sfruttare tutte le diverse ottimizzazioni a diversi livelli e le loro interazioni tra loro.
Si noti che, ad esempio, il compilatore JIT HotSpot C2 esegue effettivamente una vettorializzazione automatica, che è anche una forma di parallelizzazione automatica.