GraalVM의 Polyglot inception왜?왜냐하면 얘가 재밌어요.🏄

최초로 deepu.tech에 출판되었다.
GraalVM이라고 들어봤어요?만약 네가 없다면, 너는 마땅히 가서 보아야 한다.이것은 감동적인 기술이다. 너는 알다시피, 이런 기술은 여러 언어의 개발자로 하여금 사용에 몰입하게 할 수 있다😉
웹 사이트에서:

GraalVM is a universal virtual machine for running applications written in JavaScript, Python, Ruby, R, JVM-based languages like Java, Scala, Groovy, Kotlin, Clojure, and LLVM-based languages such as C and C++.


GraalVM이 그 중 하나입니다.Oracle에서 개발한 다중 언어 가상 시스템으로, 다중 언어 기능 외에도 상당한 성능과 적은 메모리 사용량을 가진 것으로 증명되었다.이것은 본 컴퓨터의 이미지 구축을 지원하고, 일부 현대 자바 마이크로서비스 프레임워크(예를 들어 MicronautQuarkus)는 GraalVM을 지원한다. 왜냐하면 이것은 더욱 빠른 시작 속도와 더 작은 설치 면적을 제공하기 때문에 마이크로서비스 구조의 이상적인 선택이다.
그러면 GraalVM의 기능은 무엇입니까?빨리 봅시다.

GraalVM 기능


  • Drop in JDK replacement- 일부 기준 테스트는 GraalVM이 다른 JDK 공급업체보다 빠르고 메모리 소모가 적다는 것을 보여 줍니다. 저는 개인적으로 어떤 기준 테스트도 실행하지 않았습니다.

  • Drop in NodeJS replacement- NodeJS
  • 의 엔진으로 V8 대신 GraalVM 사용
  • RubyR의 운행 시 기본
  • 보다 빠름
  • Ahead-of-time(AOT) compiled native images

  • Java(모든 JVM 언어), JavaScript, Ruby, Python, R, C/C++/Rust(LLVM) 및 언어 상호 운용성

  • Polyglot capabilities 타사 언어 지원
  • 실현

    Truffle 언어 구현 프레임워크 GraalVM 설치


    시작하기 전에 GraalVM을 설정합니다.SDKMAN을 사용했습니다. 수동으로 설치하고 싶으면 에 따라 조작할 수 있습니다.
  • 첫 번째 this 아직 없으면.
  • sdk list java
    # you can use a newer version if available
    sdk install java 19.3.1.r11-grl
    sdk use java 19.3.1.r11-grl
    # Check everything
    java -version
    node -v
    lli --version
    
    GraalVM이 설치되고 java, nodelli 컨텍스트로 설정됩니다.참고: 새 터미널 세션을 시작하면 sdk use java 19.3.1.r11-grl을 다시 실행해야 합니다.
  • LLVM 툴체인, Python 및 Ruby 지원 설치
  • gu install llvm-toolchain
    export LLVM_TOOLCHAIN=\$(lli --print-toolchain-path)
    
    gu install python
    gu install ruby
    
  • 철녹 설치
  • curl https://sh.rustup.rs -sSf | sh
    
    자, 우리 출발 준비합시다!

    SDKMAN 설치 재밌게 놀래요.


    다국어 개발자로서 GraalVM은 저에게 매우 흥미롭습니다. 왜냐하면 저는 제가 좋아하는 여러 언어를 함께 사용하고 모든 언어 중 가장 좋은 부분을 이용할 수 있기 때문입니다.GraalVM이 제공하는 다중 언어 기능을 살펴보겠습니다. Python, Ruby, R 및 Rust에 대한 지원은 아직 실험 단계이기 때문에 거리가 다를 수 있습니다.오늘은 Java, JavaScript, Ruby, Rust, Python, C++를 사용하여 프로그램을 구축합니다.

    I wanted to use Rust and Go as well. While Rust mostly works via the GraalVM lli command line, it has a lot of limitations when embedded in polyglot mode. After a lot of fiddling around, I did manage to get it working. For Golang, it might be possible with this Go LLVM compiler as shown here, but it's having its own set of issues as well when I tried. So I have given up on Golang for now. Let me know if any of you got it working.


    우리는 간단한 (어리석은) 것이 있을 것이다😉) Java로 작성된 응용 프로그램, Java에서 단계별로 다른 언어를 조합하는 방법
  • Python: 주어진 입력 그룹
  • 에서 피보나치 수 필터링
  • JavaScript: 마지막
  • 에서 출력 그룹의 각 숫자의 입방체를 찾습니다
  • C++: 이전
  • 에서 출력 그룹의 숫자의 합을 가져옵니다.
  • Rust: 이전
  • 에서 숫자의 입방근을 찾습니다
  • Ruby: 이전
  • 에서 숫자의 곱하기 찾기
  • Java: 마지막 인쇄 결과(이것도 포장 프로그램)
  • 더 복잡한 예시를 원한다면 을 보십시오.

    이것 1단계: Java


    자바 패키지 Polyglot.java부터 시작하겠습니다.
    import java.io.*;
    import org.graalvm.polyglot.*;
    
    class Polyglot {
        // We create a polyglot context to evaluate source files
        static Context polyglotCtx = Context.newBuilder().allowAllAccess(true).build();
    
        // Utility method to load and evaluate a source file
        static Value loadSource(String language, String fileName) throws IOException {
            File file = new File(fileName);
            Source source = Source.newBuilder(language, file).build();
            return polyglotCtx.eval(source);
        }
    
        // Utility method to convert arrays between languages
        static int[] getIntArrayFromValue(Value val) {
            int[] out = new int[(int) val.getArraySize()];
            if (val.hasArrayElements()) {
                for (int i = 0; i < val.getArraySize(); i++) {
                    out[i] = val.getArrayElement(i).asInt();
                }
            }
            return out;
        }
    
        public static void main(String[] args) throws IOException {
    
            int[] input = new int[] { 4, 2, 8, 5, 20, 1, 40, 13, 23 };
    
            /* PYTHON: Get the Fibonacci numbers from the array */
            loadSource("python", "pythonpart.py");
            Value getFibonacciNumbersFn = polyglotCtx.getBindings("python").getMember("getFibonacciNumbers");
            int[] fibNumbers = getIntArrayFromValue(getFibonacciNumbersFn.execute(input));
    
            /* JAVASCRIPT: Find cube of numbers in the output array */
            loadSource("js", "jspart.js");
            Value findCubeOfNumbersFn = polyglotCtx.getBindings("js").getMember("findCubeOfNumbers");
            int[] sqrNumbers = getIntArrayFromValue(findCubeOfNumbersFn.execute(fibNumbers));
    
            /* C++: Get the sum of the numbers in the output array */
            loadSource("llvm", "cpppart");
            Value getSumOfArrayFn = polyglotCtx.getBindings("llvm").getMember("getSumOfArray");
            int sum = getSumOfArrayFn.execute(sqrNumbers, sqrNumbers.length).asInt();
    
            /* Rust: Find the cube root of sum */
            Value cubeRootFn = loadSource("llvm", "rustpart.bc").getMember("cube_root");
            // println! macro does not work from Rust when embedded, some issue with mangling
            System.out.println("Rust => Find cube root of the number");
            Double cubeRoot = cubeRootFn.execute(sum).asDouble();
    
            /* RUBY: Find factorial of the number */
            Value factorialFn = loadSource("ruby", "rubypart.rb");
            long out = factorialFn.execute(cubeRoot).asLong();
    
            System.out.println("Sum: " + sum);
            System.out.println("Cube Root: " + cubeRoot);
            System.out.println("Factorial: " + out);
        }
    }
    
    실용 함수는 코드를 간소화하기 위해서입니다. 이제 함수를 구성하는 모든 절차를 살펴보겠습니다.

    2단계: Python


    우리는 파일 getFibonacciNumberspythonpart.py 함수를 실행하고 입력 그룹에 전달하고 있습니다.
    /* PYTHON: Get the Fibonacci numbers from the array */
    loadSource("python", "pythonpart.py");
    Value getFibonacciNumbersFn = polyglotCtx.getBindings("python").getMember("getFibonacciNumbers");
    int[] fibNumbers = getIntArrayFromValue(getFibonacciNumbersFn.execute(input));
    
    pythonpart.py을 봅시다. 이것은 표준적인python 프로그램으로 하나의 그룹을 가져와 그 중에서 피보나치 수를 필터한 후에 결과 그룹으로 되돌아옵니다.
    import math
    
    def isPerfectSquare(num):
        n = int(math.sqrt(num))
        return (n * n == num)
    
    # Function to check if the number is in Fibonacci or not
    def getFibonacciNumbers(array):
        print("Python => Filtering Fibonacci number from the array");
    
        out = []
        n = len(array)
        count = 0
        for i in range(n):
            if (isPerfectSquare(5 * array[i] * array[i] + 4) or
                isPerfectSquare(5 * array[i] * array[i] - 4)):
    
                out.append(array[i]);
                count = count + 1
    
        if (count == 0):
            print("None present");
    
        return out
    

    3단계: JavaScript


    우리는 파일 findCubeOfNumbersjspart.js 함수를 실행하고 Python 함수의 결과를 전달하고 있습니다.
    /* JAVASCRIPT: Find cube of numbers in the output array */
    loadSource("js", "jspart.js");
    Value findCubeOfNumbersFn = polyglotCtx.getBindings("js").getMember("findCubeOfNumbers");
    int[] sqrNumbers = getIntArrayFromValue(findCubeOfNumbersFn.execute(fibNumbers));
    
    jspart.js을 봅시다. 이것은 표준 자바스크립트 함수입니다. 이것은 하나의 수조를 받아들여 요소를 비추고 수조를 되돌려줍니다.그러나 우리는 Array.prototype.map.call이 아니라 array.map을 호출해야 한다. 왜냐하면 자바가 전달하는 수조는 표준적인 JS수조가 아니기 때문이다.
    function findCubeOfNumbers(array) {
      console.log("JS => Getting cube of numbers in the array");
    
      return Array.prototype.map.call(array, (it) => Math.pow(it, 3));
    }
    

    4단계: C++

    getSumOfArray 바이너리 파일의 cpppart 함수를 실행하고 있습니다.여기서 JS 함수의 결과와 배열의 길이를 전달합니다.우리는 파이썬, 루비, 자바스크립트와 달리 컴파일된 바이너리 파일을 사용해야 한다. 후자는 해석 언어이다.
    /* C++: Get the sum of the numbers in the output array */
    loadSource("llvm", "cpppart");
    Value getSumOfArrayFn = polyglotCtx.getBindings("llvm").getMember("getSumOfArray");
    int sum = getSumOfArrayFn.execute(sqrNumbers, sqrNumbers.length).asInt();
    
    바이너리 파일의 소스 코드는 cpppart.cpp 파일에 있습니다.다음 공식을 사용하여 컴파일하기
    export LLVM_TOOLCHAIN=$(lli --print-toolchain-path)
    $LLVM_TOOLCHAIN/clang++ -shared cpppart.cpp -lpolyglot-mock -o cpppart
    
    함수를 내보내는 데 사용되는 표준 C++ 프로그램인 cpppart.cpp을 살펴보자.그것은 수조와 그 길이를 매개 변수로 하고 숫자를 되돌려준다
    #include<iostream>
    using namespace std;
    
    // Function to find the sum of integer array
    // extern "C" is required to suppress mangling
    extern "C" int getSumOfArray(int array[], int size) {
        printf("C++ => Find sum of numbers in an array\n");
    
        int i, sum = 0;
        for(i = 0; i < size; i++) {
            sum += array[i];
        }
        return sum;
    }
    

    단계 5: 녹슨

    cube_root 함수를 실행하고 있습니다. 이 함수는 파일 rustpart.bc에 있으며 rustpart.rs으로 컴파일되었습니다.여기서 C++ 함수의 결과를 전달합니다.
    /* Rust: Find the cube root of sum */
    Value cubeRootFn = loadSource("llvm", "rustpart.bc").getMember("cube_root");
    // println! macro does not work from Rust when embedded, some issue with mangling
    System.out.println("Rust => Find cube root of the number");
    Double cubeRoot = cubeRootFn.execute(sum).asDouble();
    
    rustpart.rs을 봅시다. 이것은 표준적인 Rust 함수입니다. 숫자를 취하고 입방근을 찾아 되돌려줍니다.그러나 우리는 #[no_mangle]의 주석을 지정해야 한다. 분명히 우리는 어떤 판자 상자도 사용할 수 없다.원본 매개 변수/출력이 있는 Simples 함수는 작동할 수 있을 것 같지만, 더 복잡한 함수는 삽입할 때 작용하지 않습니다.
    #[no_mangle]
    fn cube_root(arg: f64) -> f64 {
        arg.cbrt()
    }
    
    fn main(){}
    
    우리는 rustc 로고가 있는 --emit=llvm-bc 컴파일러를 사용하여 Rust 소스 코드를 이진 코드로 컴파일합니다
    rustc --emit=llvm-bc rustpart.rs
    

    6단계: 루비


    우리는 파일 factorialrubypart.rb 함수를 실행하고 있습니다.여기서 Rust 함수의 결과를 전달합니다.
    /* RUBY: Find factorial of the number */
    Value factorialFn = loadSource("ruby", "rubypart.rb");
    long out = factorialFn.execute(cubeRoot).asLong();
    
    rubypart.rb을 봅시다. 이것은 표준적인 Ruby lambda 함수입니다. 숫자를 받아들여 곱셈으로 돌아갑니다.
    factorial = -> (num) {
        puts "Ruby => Find factorial of the number"
        (1..num).inject {|product, num| product * num }
    }
    
    마지막으로 Java로 출력을 인쇄합니다.

    실행 프로그램


    이 프로그램을 실행하기 위해서는 먼저 C++, Rust 및 Java 파일을 컴파일한 다음 GraalVM에서 제공하는 JVM을 사용하여 실행해야 합니다.run.sh으로 저장하고 실행할 수 있는 단계는 다음과 같습니다.
    export LLVM_TOOLCHAIN=$(lli --print-toolchain-path)
    $LLVM_TOOLCHAIN/clang++ -shared cpppart.cpp -lpolyglot-mock -o cpppart || exit
    
    rustc --emit=llvm-bc rustpart.rs || exit
    
    javac Polyglot.java && java Polyglot
    
    다음과 같은 출력이 생성됩니다.

    결론


    이거 재밌지 않아요?그럼, 이런 다중 언어 능력이 유용합니까?이것은 상황에 따라 결정됩니다. GraalVM의 다국어 기능은 아직 생산 준비가 되지 않았지만 여전히 유용합니다. 왜냐하면 진정한 언어 상호작용성을 위해 문을 열었기 때문입니다. 프로그램의 모든 언어를 사용할 수 있는 라이브러리를 상상해 보세요. 이것은 많은 C, Ruby, R,GraalVM이 있는 JS와 Java 라이브러리는 지원이 향상됨에 따라 한 언어에 국한된 제한에서 벗어날 수 있습니다.예를 들어 루비와 같은 언어에 대해 GraalVM은 표준 CRuby나 JRuby보다 훨씬 빠른 것 같다. 이것은 프로그램에 여러 언어를 삽입할 때 비용을 너무 걱정할 필요가 없다는 것을 의미하기 때문이다.
    GraalVM은 제가 최근에 만났던 가장 혁명적인 기술 중 하나입니다. 저는 Polyglot 언어 지원이 곧 생산에 들어갈 수 있고 원본 이미지 기능까지 합치면 진정한polyglot 응용 프로그램의 강력한 플랫폼이 될 수 있기를 바랍니다.
    만약 당신이 이 문장을 좋아한다면, 좋아하거나 평론을 남겨 주세요.
    너는 나를 따라갈 수 있다.
    표지 이미지 신용: 각 프로젝트의 공식 로고를 바탕으로 한다.

    좋은 웹페이지 즐겨찾기