являются ли такие компиляторы, как Javac, достаточно умными, чтобы определять, когда метод является чистой функцией.
Это не вопрос "достаточно умен". Это называется анализом чистоты и в общем случае доказуемо невозможно: это эквивалентно решению проблемы остановки.
Теперь, конечно, оптимизаторы все время делают доказуемо невозможные вещи, «доказуемо невозможные в общем случае» не означает, что они никогда не работают, это лишь означает, что они не могут работать во всех случаях. Итак, на самом деле существуют алгоритмы для проверки, является ли функция чистой или нет, просто чаще всего результатом будет «Я не знаю», что означает, что по соображениям безопасности и правильности, вы должны предположить, что эта конкретная функция может быть нечистой.
И даже в тех случаях , когда он делает работу, алгоритмы являются сложными и дорогостоящими.
Итак, это проблема № 1: она работает только для особых случаев .
Проблема № 2: Библиотеки . Чтобы функция была чистой, она может вызывать только чистые функции (и эти функции могут вызывать только чистые функции и т. Д. И т. Д.). Javac, очевидно, знает только о Java, и он знает только о коде, который он может видеть. Таким образом, если ваша функция вызывает функцию в другом модуле компиляции, вы не можете знать, является ли она чистой или нет. Если он вызывает функцию, написанную на другом языке, вы не можете знать. Если это вызывает функцию в библиотеке, которая может даже не быть установлена, вы не можете знать. И так далее.
Это работает, только если у вас есть анализ всей программы, когда вся программа написана на одном языке, и все компилируется сразу за один раз. Вы не можете использовать любые библиотеки.
Проблема № 3: Планирование . После того, как вы выяснили, какие части являются чистыми, вам все равно нужно запланировать их для разделения потоков. Или не. Запуск и остановка потоков очень дороги (особенно в Java). Даже если вы сохраняете пул потоков и не запускаете и не останавливаете их, переключение контекста потоков также является дорогостоящим. Вы должны быть уверены, что вычисления будут выполняться значительно дольше, чем требуется для планирования и переключения контекста, иначе вы потеряете производительность, а не увеличите ее.
Как вы, наверное, уже догадались, вычисление того, сколько времени займет вычисление, в общем случае невозможно доказать (мы даже не можем понять, займет ли это конечное количество времени, не говоря уже о том, сколько времени), а также трудно и дорого даже в особый случай.
В стороне: Javac и оптимизации . Обратите внимание, что большинство реализаций javac на самом деле не выполняют много оптимизаций. Например, реализация Oracle Javac опирается на базовый механизм выполнения для оптимизации . Это приводит к другому набору проблем: скажем, javac решил, что определенная функция является чистой и достаточно дорогой, и поэтому он компилирует ее для выполнения в другом потоке. Затем появляется оптимизатор платформы (например, JIT-компилятор HotSpot C2), который оптимизирует всю функцию. Теперь у вас есть пустой поток, ничего не делая. Или, представьте, опять же, javac решает запланировать функцию в другом потоке, и оптимизатор платформы может полностью оптимизировать его, за исключением того, что он не может выполнять встраивание через границы потоков, поэтому функция, которая может быть полностью оптимизирована, теперь выполняется без необходимости.
Таким образом, делать что-то подобное действительно имеет смысл, только если у вас есть один компилятор, выполняющий большинство оптимизаций за один раз, чтобы компилятор знал и мог использовать все различные оптимизации на разных уровнях и их взаимодействия друг с другом.
Следует отметить , что, например, компилятор HotSpot С2 JIT фактически делает выполнять некоторые автоматической векторизации, который также является одной из форм автоматического распараллеливания.