Почему scalac не оптимизирует накладные расходы в простых конструкциях for?

Вот пример фрагмента кода, который на первый взгляд выглядит так, будто scalac мог бы легко его оптимизировать:

val t0 = System.nanoTime()
for (i <- 0 to 1000000000) {}
val t1 = System.nanoTime()
var i = 0
while (i < 1000000000) i += 1
val t2 = System.nanoTime()

println((t1 - t0).toDouble / (t2 - t1).toDouble)

Приведенный выше код печатает 76.30068413477652, и соотношение, похоже, ухудшается по мере увеличения количества итераций.

Есть ли какая-то особая причина, по которой scalac предпочитает не оптимизировать for (i <- L to/until H) в любую форму байт-кода, которую javac генерирует для for (int i = L; i < H; i += 1)? Может быть, это потому, что Scala предпочитает делать вещи простыми и ожидает, что разработчик просто прибегнет к более производительным формам, таким как цикл while, когда требуется чистая скорость цикла? Если да, то почему это хорошо, учитывая частоту таких простых циклов for?


person Erik Kaplun    schedule 23.09.2013    source источник
comment
Потому что это не так просто. Компилятор должен знать, как реализация foreach выглядит для объекта, который вы передаете. Есть много вещей, которые могут пойти не так с такой оптимизацией.   -  person drexin    schedule 23.09.2013
comment
Определенно, но это может быть по крайней мере частный случай <Int> to/until <Int> — разве такая информация не доступна статически во время компиляции с достаточной надежностью?   -  person Erik Kaplun    schedule 23.09.2013
comment
Ознакомьтесь с Spire cfor и cforRange, которые обеспечивают именно такую ​​оптимизацию с помощью макросов.   -  person Travis Brown    schedule 23.09.2013
comment
Ага, я на самом деле уже задавался вопросом, можно ли использовать макросы, чтобы обойти это :) Хотя я действительно хотел бы, чтобы макросы cfor могли просто оптимизировать существующие конструкции for (...), что, я уверен, могут сделать макросы Lisp.   -  person Erik Kaplun    schedule 23.09.2013
comment
См. также Scalaxy. У меня не было возможности попробовать это в последнее время, но там есть кое-что интересное.   -  person Travis Brown    schedule 23.09.2013
comment
@ErikAllik: jvm может встроить метод foreach. после встраивания вы получите цикл while. Эта оптимизация работает не только для диапазонов. Scalac не должен знать о классе Range - это не часть самого языка. Как уже отмечалось, в крайне редких случаях, когда вам действительно нужны такие оптимизации во время компиляции, вы можете использовать сторонние библиотеки, такие как Scalaxy.   -  person senia    schedule 23.09.2013


Ответы (1)


Производительность for-comprehension в Scala сейчас является очень долгой дискуссией.

См. следующие ссылки:

TL,DR: команда Scala решила сосредоточиться на более общих оптимизациях, чем те, которые должны были бы отдавать предпочтение некоторым конкретным классам и пограничным случаям (в данном случае: Range).

person Piotr Kołaczkowski    schedule 23.09.2013
comment
Так будут ли более общие оптимизации когда-либо каким-то образом обрабатывать случай Range? Даже в теории? - person Erik Kaplun; 23.09.2013
comment
@ErikAllik: @inline аннотация на foreach метод. - person senia; 23.09.2013