2010-09-30 3 views
7

Я работаю над аналитической системой Scala (http://www.hiringthing.com), и я обнаружил, что часто задаю себе следующий вопрос. Учитывая «чистую» функцию без побочных эффектов, если я дважды ударяю эту функцию с теми же входами, могу ли я ожидать, что компилятор будет повторно использовать значение, сгенерированное с первого запуска, или снова проведет весь код. Иными словами, первый пример ниже более эффективный, чем второй?Насколько эффективен компилятор Scala для повторного использования результатов известных функций?

def add(x: Int, y: Int) = x + y * 10000000000 

val a = add(1,2) 
do_something(a) 
do_another_thing(a) 

против

def add(x: Int, y: Int) = x + y * 10000000000 

do_something(add(1,2)) 
do_another_thing(add(1,2)) 

Если компилятор действительно может оптимизировать второй случай, есть ограничивает сложности функции?

То, что я хочу сделать, это избежать запуска тяжелых функций наверняка математики несколько раз просто ради удобства программирования ...

Благодаря

+0

javap может помочь заглянуть в код байта, созданный компилятором. Я сомневаюсь, что текущий компилятор выполнит оптимизацию, просто потому, что без monads трудно определить, имеет ли код какие-либо побочные эффекты, но я могу ошибаться. –

ответ

9

Из того, что я видел, компилятор Scala не оптимизирует это вообще. JVM может, если он может определить, что результаты не изменятся, но часто у него нет хорошего способа узнать.

Итак, в общем случае, если это тривиальное вычисление, это не имеет никакого значения, так как это тривиально, и потому, что JVM может понять, что это нужно сделать только один раз. Если это сложно и скорость очень важна, вы должны использовать метод val a =, если у вас нет тестов, которые демонстрируют вам, что JVM достаточно умен в этом случае.

Обратите внимание, что иногда бывает неудобно размещать vals. Есть два способа обойти это. Во-первых, обратите внимание, что почти все может быть заменено эквивалентным выражением в фигурных скобках, поэтому исключения могут быть реже, чем вы думаете. Кроме того, этот метод может быть полезен при определенных обстоятельствах:

def reuse[A,B](a: A)(f: A => B) = f(a) 
reuse(add(1,2))(a => { do_something(a); do_another_thing(a)}) 
+1

В течение длинных традиций Лиспа и Хаскеля эту функцию «повторного использования» следует, вероятно, называть «let» –

+0

Да, возможно, так. –

5

Скала компилятор не пытается оптимизировать любой через вызовы функций или методов, если вы специально не используете аннотацию @inline (и даже это не поддерживается). Тем не менее, JVM и компилятор Hotspot JIT, в частности, почти наверняка смогут встроить вызов «добавить» в ваши примеры и затем смогут удалить результирующие общие подвыражения.

Как всегда, когда вы задаете вопросы об оптимизации производительности и компиляторах, ответы не должны приниматься как госпел без обширного профессионального теста. Прошлая производительность не гарантирует будущих возвратов. Содержание может быть установлено во время транспортировки. Если опухоль сохраняется через четыре часа, обратитесь к врачу. Все модели старше 18.

+2

Вы забыли «или 21 где требуется». –

5

Без системы эффекта, компилятор просто не может решить, повторно использовать метод (или Function) возвращаемые значения.

Как и в большинстве языков на протяжении всей истории вычислений, вам необходимо устранить избыточность из ваших алгоритмов.

Смежные вопросы