Чи запобігає JVM оптимізація виклику хвоста?


99

Я побачив цю цитату на запитанні: що є хорошою функціональною мовою, на якій можна побудувати веб-сервіс?

Зокрема, Scala не підтримує усунення хвостових викликів, за винятком саморекурсивних функцій, що обмежує види композиції, яку ви можете виконати (це фундаментальне обмеження JVM).

Це правда? Якщо так, то що з СВМ створює це фундаментальне обмеження?

Відповіді:


74

Цей пост: рекурсія чи ітерація?може допомогти.

Коротше кажучи, оптимізацію хвостових викликів важко зробити в JVM через модель безпеки та необхідність завжди мати доступ до сліду стека. Ці теорії теоретично можна підтримати, але це, ймовірно, вимагатиме нового байт-коду (див . Неофіційну пропозицію Джона Роуза ).

Існує також більше обговорення в програмі Sun bug # 4726340 , де оцінка (від 2002 р.) Закінчується:

Я вважаю, що це все-таки можна зробити, але це не мале завдання.

Наразі триває робота над проектом « Машина Да Вінчі ». Статус підпроекту хвостового виклику вказаний як "прото 80%"; навряд чи вдасться перетворити його на Java 7, але я думаю, що у Java 8 це дуже хороший шанс.


Я не зовсім дотримувався пояснення. Я подумав, що оптимізація хвостових викликів була здійснена компілятором. Якщо припустити, що у вас є функція, яка може бути оптимізована компілятором, то ви також можете мати еквівалентну нерекурсивну функцію, яка реалізує ту саму функціональність, використовуючи цикл, правильно? Якщо так, не вдалося цього зробити компілятором. Я не в змозі прослідкувати залежність від СВМ. Як це порівнюється з компілятором схеми, який генерував нативний код i386?
Gautham Ganapathy

4
@Gautham: Моє твердження про налагодження стосувалося використання батутів як вирішення проблеми відсутності усунення хвостових викликів у JVM. Усунення хвостових викликів може і було здійснено на JVM (Арнольд Шайгхофер зробив у OpenJDK, а також LLVM), тому не виникає питання, чи можна це зробити. Зрозуміло, CLR Microsoft підтримує усунення хвостових викликів протягом 10 років, а випуск F # продемонстрував, що це зміна ігор. Я думаю, що відповідь полягає в тому, що СП вже давно застоюється.
JD

3
Це поширене оману та часто повторне виправдання, але неправильне. Протягом багатьох років було добре встановлено, що безпека шляхом перевірки стека (та надання корисних слідів стека) не сумісна з правильними викликами хвоста. Наприклад, див цей документ від 2004 citeseerx.ist.psu.edu/viewdoc / ... Downvoting, так як відповідь невірна.
Джастін Шихі

5
@JustinSheehy: Що неправильно? Питання було: "Чи запобігає JVM оптимізація хвостових викликів?" А відповідь - "Ні, але важко".
Майкл Майерс

5
чи знаєте ви, якщо в java8 це включено?
nachokk

27

Принциповим обмеженням є просто те, що JVM не надає хвостові дзвінки в своєму байтовому коді, і, отже, немає прямого способу для мови, побудованої на JVM, самому надавати хвостові дзвінки. Є обхідні шляхи, які можуть домогтися аналогічного ефекту (наприклад, батут), але вони стають серйозною ціною жахливої ​​продуктивності та заплутують створений проміжний код, який робить налагоджувач марним.

Таким чином, JVM не може підтримувати жодних функціональних мов програмування, доки Sun не реалізує хвостові дзвінки в самому JVM. Вони обговорювали це протягом багатьох років, але я сумніваюся, що вони коли-небудь будуть виконувати хвостові дзвінки: це буде дуже важко, оскільки вони передчасно оптимізували свій VM перед тим, як реалізувати такі основні функціональні можливості, а зусилля Sun сильно орієнтовані на динамічні мови, а не на функціональні мови.

Отже, існує дуже вагомий аргумент, що Scala не є справжньою функціональною мовою програмування: ці мови вважали хвостові дзвінки важливою особливістю з моменту введення схеми вперше 30 років тому.


5
Hence there is a very strong argument that Scala is not a real functional programming language - аргумент насправді досить слабкий. Звичайно tail calls [as] an essential feature, і добре, якщо базове обладнання (або віртуальна машина) підтримує його безпосередньо. Але це деталі реалізації.
Інго

8
@Ingo: Тільки якщо ви не вважаєте, що переповнення стека у вашій програмі під час роботи, сприйняте користувачем, є значною проблемою. Згідно з його відстежувачем помилок, навіть сам компілятор Scala зазнав переповнення стека. Тож навіть найдосвідченіші розробники Scala як і раніше помиляються ...
JD

7
Добре бути адвокатом, скажімо, F #. Але я відзначав вас давно (навіть за рік до використання в usenet) за те, що ви вороже ставитесь до всього, що не є F #, і все ж ваші розробки показують, що ви не знаєте, про що говорите. Як ось тут: ваш аргумент здається, що мова, на якій я можу написати програму, яка перериває переповнення стека, не є функціональною? Але чи не міг би бути такий самий аргумент для мов, де я можу спровокувати переповнення купи? Отже, святий F # сам по собі не вважатиметься функціональним.
Інго

7
@Ingo: Деякі ідіоми функціонального програмування, як взаємна рекурсія та стиль проходження продовження, можуть вимагати усунення хвостових викликів для роботи. Без цього ваші програми будуть стека переповнення. Якщо мова не може надійно запустити ідіоматичний функціональний код, чи функціональна вона? Відповідь - це, як ви кажете, заклик судження, але важлива відмінність на практиці. Martin Trojer щойно опублікував цікаве повідомлення про це у блозі
JD

2
все-таки, тільки тому, що JVM (на жаль, жодних питань) не може робити хвостові дзвінки, це не означає, що усунення хвостових викликів неможливо. Це так, як якщо б хтось заявив, що обчислення з плаваючою комою можливі лише на комп'ютерах з FPU.
Інго

22

Scala 2.7.x підтримує оптимізацію зворотного виклику для саморекурсії (функція, що викликає себе) кінцевих методів та локальних функцій.

Scala 2.8 також може забезпечити бібліотечну підтримку батута, що є методикою оптимізації взаємно рекурсивних функцій.

Чималу інформацію про стан рекурсії Scala можна знайти в блозі Річа Даґерті .


Чи можете ви, будь ласка, оновити питання про поточний статус масштабу?
om-nom-nom

@ om-nom-nom AFAIK, нічого не змінилося, ні на стороні Scala, ні на стороні JVM.
Даніель К. Собрал

8

На додаток до папери, зв'язаної в Lambda The Ultimate (за посиланням mmyers, розміщеним вище), Джон Роуз від Sun має ще щось сказати про оптимізацію хвостових викликів.

http://blogs.oracle.com/jrose/entry/tail_calls_in_the_vm

Я чув, що він може бути запроваджений на JVM колись. Підтримка хвостового дзвінка серед іншого розглядається на машині Da Vinci.

http://openjdk.java.net/projects/mlvm/


0

Усі джерела вказують на те, що JVM не в змозі оптимізувати у випадку хвостової рекурсії, але, прочитавши налаштування продуктивності Java (2003, O'reilly), я виявив автора, який стверджує, що він може досягти більшої продуктивності рекурсії за допомогою впровадження хвостової рекурсії.

Ви можете знайти його претензію на сторінці 212 (пошук "рекурсій хвоста", це повинен бути другим результатом). Що дає?


IBM підтримує певну форму TCO в їх впровадженні JVM (як оптимізація, тому немає гарантій). Можливо, автори налаштування Java Performance подумали, що ця функція врешті-решт буде впроваджена всіма JVM. ibm.com/developerworks/java/library/j-diag8.html
llemieng
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.