GraalVM — это, среди прочего, среда выполнения на полиглотском языке. Он может запускать приложения, написанные на многих языках — на языках JVM, таких как Java, Scala, Groovy и Kotlin, а также на языках, отличных от JVM, таких как Python, R, Ruby, JavaScript и LLVM. GraalVM также позволяет приложениям на любом из этих языков выполнять фрагменты кода, написанные на любом из других поддерживаемых им языков. Это похоже на таксиста, который может говорить на многих языках, а также прекрасно понимает вас, когда вы начинаете вставлять фрагменты разных языков, пытаясь объяснить, куда вы хотите ехать.

В этой статье я кратко рассмотрю взаимодействие полиглотов на GraalVM из Python с другими языками, в частности с Java, JavaScript и R (лишь поверхностно). Реализация Python на GraalVM является совершенно новой на данном этапе (октябрь 2019 г.) и имеет ограниченную поддержку многих языковых функций. Он еще не подходит для использования в производстве. Как указано на сайте GraalVM:

Реализация Python в GraalVM находится на ранних стадиях разработки. Основная цель — поддержка SciPy и входящих в нее библиотек, но до этого нам еще далеко. На данный момент реализация Python доступна для экспериментов и любопытных конечных пользователей. В настоящее время GraalVM стремится быть совместимой с Python 3.7, но до этого еще далеко, и весьма вероятно, что любая программа Python, требующая импорта, столкнется с чем-то неподдерживаемым.

Забавно то, что когда вы обращаетесь к Java, JavaScript и R, код интерпретируется более зрелыми движками: производственные приложения Java и JavaScript сегодня работают на GraalVM.

Ниже показана отличная визуализация того, что означает запуск Python на GraalVM с точки зрения базовых компонентов. анализируется в абстрактное синтаксическое дерево Truffle, представленное в байт-коде Java. Любой не-JVM-язык, на котором работает GraalVM, анализируется в такой AST. Среда выполнения GraalVM знает, как запускать эти деревья. А клей-полиглот в GraalVM умеет объединять деревья перед их выполнением.

Пример приложения Python демонстрирует ряд аспектов взаимодействия полиглотов с Python:

  • как оценивать фрагменты кода на разных языках (Java, R, JavaScript, Ruby)
  • как выполнить объект функции, возвращенный из другого языка
  • как помещать объекты — объекты данных и функции — в карту Polyglot, которая живет между всеми языками-полиглотами, исполняемыми на GraalVM
  • как извлекать объекты из карты Polyglot — читать и записывать их или выполнять

R, Ruby и JavaScript из Python

В каждом случае фрагмент кода оценивается во время выполнения, и результат сравнения с соответствующим языковым движком возвращается в программу Python, готовый для проверки и дальнейших манипуляций.

Java из Python

Совместимость Java работает немного иначе, чем взаимодействие полиглота с языками, отличными от JVM (или Truffle). Классы Java — пользовательские и сторонние библиотеки — предоставляются в параметре пути к классам, передаваемом в graalpython. Все стандартные API Java 8 доступны в любое время.

JavaScript из Python — использование карты Polyglot

В этом фрагменте переменная title помещена в карту Polyglot с функцией export_value под ключом «title». Затем оценивается фрагмент JavaScript. Это приводит к созданию анонимной функции, которая впоследствии возвращается в Python. В Python функция печатается и выполняется. Результат сохраняется в переменной msg и, наконец, выводится значение этой функции.

Результат запуска этого фрагмента показан здесь. Вторая строка создается внутри функции JavaScript. Это показывает, что код JavaScript успешно импортировал заголовок из карты Polyglot.

JavaScript и R из Python — перенос функций через языковые барьеры

Следующий фрагмент еще более запутан: оценивается фрагмент JavaScript. Он экспортирует определение функции в карту полиглота под ключом squared. Функция импортируется из карты в Python и выполняется из Python. Затем оценивается фрагмент кода R; этот фрагмент также создает функцию, которую он оценивает. В этом фрагменте код R импортирует функцию squared из карты Polyglot (помещенной туда фрагментом JavaScript) и выполняет ее. Он также импортирует название с карты и печатает его на выходе. Функция, возвращенная из фрагмента R, выполняется в Python (и косвенно выполняет то, что было определено в JavaScript).

Вывод из этого конкретного фрагмента кода Python

Чтобы запустить все приложение на GraalVM:

graalpython --polyglot --jvm ./python_polyglot.py

GraalPython — это механизм выполнения Python на GraalVM. Параметр полиглота указывает, что совместимость с многоязычным языком активна, и в настоящее время для использования JVM в качестве платформы выполнения требуется переключатель jvm: для взаимодействия с другими языками мы должны были предоставить аргумент -jvm выше. Это указывает программе запуска работать на JVM, а не в режиме Native Image — вы заметите более длительное время запуска, чем с механизмом выполнения graalpython для собственного образа (существенно дольше).

Если мы хотим вызывать объекты Java, определенные за пределами API Java 8, мы должны предоставить их Graalpython, указав параметр командной строки -vm.cp=‹разделенный двоеточием список JAR-файлов, каталогов›.

Результат запуска приложения:

Ресурсы

Репозиторий GitHub с исходниками для этой статьи: https://github.com/AMIS-Services/jfall2019-graalvm

Документы GraalVM по Graal Python — https://www.graalvm.org/docs/reference-manual/languages/python/

Документы GraalVM — совместимость с Python — https://www.graalvm.org/docs/reference-manual/languages/python/#interoperability

GraalVM Docs — Polyglot, включая Python в качестве целевого и исходного языка: https://www.graalvm.org/docs/reference-manual/polyglot/

GitHub Домашняя страница GraalPython — https://github.com/graalvm/graalpython

Введение в реализацию Python для GraalVM — https://medium.com/graalvm/how-to-contribute-to-graalpython-7fd304fe8bb9

JavaDocs для GraalVM Polyglot — https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/package-summary.html

Первоначально опубликовано на https://technology.amis.nl 30 октября 2019 г.