są kompilatorami takimi jak Javac, wystarczająco inteligentnymi, by wykryć, kiedy metoda jest czystą funkcją.
To nie jest kwestia „wystarczająco inteligentna”. Nazywa się to analizą czystości i jest niemożliwe do udowodnienia w ogólnym przypadku: jest to równoważne z rozwiązaniem problemu zatrzymania.
Teraz, oczywiście, optymalizatory robią rzeczy niemożliwe do udowodnienia przez cały czas, „niemożliwe do udowodnienia w ogólnym przypadku” nie oznacza, że nigdy nie działa, to tylko oznacza, że nie może działać we wszystkich przypadkach. Istnieją więc algorytmy do sprawdzania, czy funkcja jest czysta, czy nie, po prostu częściej wynikiem jest „Nie wiem”, co oznacza, że ze względów bezpieczeństwa i poprawności należy założyć że ta konkretna funkcja może być nieczysta.
I nawet w przypadkach, gdy to robi pracę, algorytmy są skomplikowane i kosztowne.
To jest problem nr 1: działa tylko w szczególnych przypadkach .
Problem nr 2: Biblioteki . Aby funkcja była czysta, może ona zawsze wywoływać tylko funkcje czyste (i te funkcje mogą wywoływać tylko funkcje czyste itd.). Javac oczywiście wie tylko o Javie i wie tylko o kodzie, który widzi. Tak więc, jeśli twoja funkcja wywołuje funkcję w innej jednostce kompilacyjnej, nie możesz wiedzieć, czy jest czysta, czy nie. Jeśli wywołuje funkcję napisaną w innym języku, nie możesz tego wiedzieć. Jeśli wywołuje funkcję w bibliotece, która może nawet nie zostać jeszcze zainstalowana, nie możesz tego wiedzieć. I tak dalej.
Działa to tylko wtedy, gdy masz analizę całego programu, gdy cały program jest napisany w tym samym języku i wszystko jest kompilowane za jednym razem. Nie możesz używać żadnych bibliotek.
Problem nr 3: Planowanie . Po ustaleniu, które części są czyste, nadal musisz zaplanować je dla oddzielnych wątków. Albo nie. Uruchamianie i zatrzymywanie wątków jest bardzo kosztowne (szczególnie w Javie). Nawet jeśli utrzymujesz pulę wątków i nie uruchamiasz ich ani nie zatrzymujesz, przełączanie kontekstu wątków jest również drogie. Musisz mieć pewność, że obliczenia będą działały znacznie dłużej niż czas potrzebny na zaplanowanie i zmianę kontekstu, w przeciwnym razie stracisz wydajność, a nie ją zyskasz.
Jak zapewne już się domyślacie, ustalenie, jak długo potrwa obliczenie, jest ogólnie niemożliwe (nie możemy nawet ustalić, czy zajmie to skończoną ilość czasu, nie mówiąc już o tym, ile czasu), a także trudne i kosztowne, nawet w specjalny przypadek.
Na bok: Javac i optymalizacje . Zauważ, że większość implementacji javac w rzeczywistości nie wykonuje wielu optymalizacji. całkowicie go zoptymalizuj, z wyjątkiem tego, że nie może wykonywać wstawiania ponad granicami wątków, a zatem funkcja, którą można całkowicie zoptymalizować, jest teraz niepotrzebnie wykonywana.Na przykład implementacja javac przez Oracle polega na bazowym silniku wykonawczym w celu optymalizacji . Prowadzi to do kolejnego zestawu problemów: powiedzmy, javac zdecydował, że określona funkcja jest czysta i wystarczająco droga, więc kompiluje ją do wykonania na innym wątku. Następnie pojawia się optymalizator platformy (na przykład kompilator HotSpot C2 JIT) i optymalizuje całą funkcję. Teraz masz pusty wątek, który nic nie robi. Albo wyobraź sobie, że javac postanawia zaplanować funkcję w innym wątku, a optymalizator platformy mógłby to zrobić
Tak więc robienie czegoś takiego ma sens tylko wtedy, gdy masz jeden kompilator, który wykonuje większość optymalizacji za jednym razem, aby kompilator wiedział i mógł wykorzystać wszystkie różne optymalizacje na różnych poziomach i ich interakcje między sobą.
Należy zauważyć, że, na przykład, kompilator JIT HotSpot C2 rzeczywiście ma wykonać pewne auto wektoryzacji, który jest również formą auto-zrównoleglenia.