Hệ sinh thái GraalVM bao gồm một bộ ngôn ngữ rất thú vị. Mã bit JavaScript, Ruby, Python, WebAssugging, Java, LLVM, v.v. Tất cả đều mang lại những lợi thế riêng. Python trên GraalVM mở ra hệ sinh thái phong phú gồm các thư viện khoa học dữ liệu Python cho các nhà phát triển Java. Mặc dù hỗ trợ Python trên GraalVM vẫn đang ở giai đoạn thử nghiệm, nhưng bạn có thể sử dụng nó ngay hôm nay để mở rộng các ứng dụng Java của mình bằng mã Python và thư viện
Trong bài viết này, chúng ta xem xét một ứng dụng ví dụ được phát triển bởi các sinh viên tại Viện Hasso Plattner [HPI] ở Potsdam, ứng dụng này có thể được sử dụng làm mẫu để sử dụng các thư viện Python từ Java trên GraalVM. Mã nguồn đầy đủ có sẵn tại kho GitHub của HPI Software Architecture Group
Nếu bạn muốn tìm hiểu thêm ngữ cảnh về ứng dụng được mô tả trong bài viết này, cách triển khai Graalpython, hiệu suất của nó và hơn thế nữa, hãy xem Sử dụng Python từ Java với GraalVM
Sử dụng Maven để làm PythonMẫu này là một ứng dụng Java AWT mẫu có thể hiển thị các hàm nhị thức bằng thư viện PyGal Python. Hãy xem qua mã của mẫu. Lưu ý rằng chúng tôi đã đơn giản hóa nó một chút vì mục đích rõ ràng
Câu hỏi đầu tiên là - làm thế nào để bắt đầu? . Để tích hợp Python hoạt động trơn tru, chúng tôi xem xét các khía cạnh sau khi viết POM
- Dự án phải chạy trên GraalVM có cài đặt Python
- Tất cả các phụ thuộc Python được khai báo trong POM và được cài đặt khi chạy Maven, giống như các phụ thuộc Java
- Các gói và tệp Python bắt buộc phải được đưa vào tài nguyên của ứng dụng của chúng tôi
Cách duy nhất được hỗ trợ để chạy Python trên GraalVM là sử dụng các bản dựng GraalVM và cài đặt thành phần Python. Đảm bảo chúng tôi chạy trên GraalVM trong dự án Maven khá đơn giản. Chúng tôi sử dụng maven-enforcer-plugin
để kiểm tra xem biến môi trường JAVA_HOME
có trỏ đến bản phân phối GraalVM không. Điều này cũng sẽ hữu ích khi chúng ta muốn tương tác với các công cụ ngôn ngữ Python trong cây GraalVM
Cấu hình trên kiểm tra tệp thực thi `graalpython` trong thư mục `JAVA_HOME` và nếu không tìm thấy, quá trình xây dựng sẽ thất bại với thông báo lỗi hữu ích
Thêm vũ trụ gói PythonViệc cài đặt các gói Python với Maven liên quan nhiều hơn một chút và yêu cầu một chút hiểu biết về cách các ứng dụng Python thường được đóng gói và phân phối. Các gói và thư viện Python có thể được cài đặt trên toàn hệ thống hoặc cho mỗi người dùng, nhưng điều đó hiếm khi được mong muốn nếu chúng ta muốn phân phối các ứng dụng độc lập và tránh xung đột với phần còn lại của hệ thống. Vì lý do đó, cộng đồng Python khuyến nghị sử dụng mô-đun venv
Python để tạo môi trường ảo cho các dự án của bạn. Mô-đun venv
là một phần của thư viện chuẩn Python 3. Người dùng phiên bản Python 2 cũ hơn có thể nhớ gói virtualenv
phục vụ cùng mục đích nhưng nằm ngoài thư viện chuẩn Python
Môi trường ảo được tạo đơn giản bằng cách chạy mô-đun venv
với tên thư mục mà môi trường sẽ được tạo. Môi trường ảo Python ban đầu chỉ là một tập hợp các tập lệnh và liên kết tượng trưng cho thời gian chạy Python biết nơi cài đặt và tải các gói. Sau khi được tạo, môi trường ảo có trình khởi chạy pip
trong thư mục bin
có thể được sử dụng để cài đặt các gói Python từ PyPI vào môi trường
Để chuẩn bị môi trường ảo, chúng tôi sử dụng exec-maven-plugin
. Chúng tôi gọi mô-đun venv
đã được vận chuyển cùng với GraalVM Python của chúng tôi [được tìm thấy trong JAVA_HOME
như được đảm bảo ở trên], sau đó sử dụng trình khởi chạy pip
để cài đặt PyGal, do đó đảm bảo rằng một maven-enforcer-plugin
3 đơn giản sẽ cài đặt các gói Python cần thiết
Gói tài nguyên được tích hợp vào Maven như một mối quan tâm cốt lõi, vì vậy chúng ta chỉ cần hiểu những tài nguyên đó là gì trong trường hợp của Python. Khi chúng tôi tạo một môi trường ảo, một cấu trúc thư mục đã được tạo bao gồm các trình khởi chạy và các gói chúng tôi đã cài đặt. Bạn có thể muốn cắt giảm kích thước bằng cách chỉ gói các gói. Điều này là không nên, tuy nhiên
Python và công cụ của nó được xây dựng xung quanh dòng lệnh và môi trường ảo cũng vậy. Trên thực tế, môi trường ảo sử dụng chính các tệp thực thi làm điểm đánh dấu cho nơi tìm gói. Vì chúng tôi không muốn dựa vào việc triển khai chính xác cách thức hoạt động của tính năng này nên chúng tôi chỉ gói gọn mọi thứ
Kết nối Java với PythonHàm maven-enforcer-plugin
4 tạo khung AWT đơn giản với khung vẽ SVG và trường nhập nơi người dùng có thể nhập công thức. Chúng tôi sử dụng API nhúng GraalVM để tạo bối cảnh Python và tải mã thư viện của chúng tôi. Trong phần gọi lại của trường đầu vào, chúng tôi gọi một hàm Python để tạo dữ liệu SVG mới mà chúng tôi đẩy vào canvas SVG để hiển thị
Điều thú vị đầu tiên là cách sử dụng API nhúng chính xác với môi trường ảo Python mà chúng tôi đã tạo. Để làm như vậy, chúng ta phải đặt một vài tùy chọn trước khi tạo GraalVM maven-enforcer-plugin
5
Hãy đi qua điều này. Đầu tiên, chúng tôi tạo một maven-enforcer-plugin
6 và yêu cầu ngôn ngữ "python" có sẵn. [Nhiều ngôn ngữ được kích hoạt ngầm. Ví dụ: Python phụ thuộc vào ngôn ngữ "llvm" để hỗ trợ tiện ích mở rộng C của nó. ] Tiếp theo, chúng tôi đặt cờ để cho phép tất cả quyền truy cập vào mã gốc, hệ thống tệp, v.v. Bây giờ bạn có thể bắt đầu với tất cả các quyền để mọi thứ diễn ra suôn sẻ và giảm bớt những gì chúng ta cần sau này
Hai cuộc gọi maven-enforcer-plugin
7 đi đôi với nhau và cần thêm một chút nền tảng Python. Python có thể thực thi được trên máy của bạn, như một phần của mã khởi động, thực thi tương đương với maven-enforcer-plugin
8. Mô-đun maven-enforcer-plugin
9 chịu trách nhiệm thiết lập đường dẫn gói cho gói người dùng và gói hệ thống, cũng như khám phá xem tệp thực thi có nằm trong môi trường ảo hay không và sau đó thiết lập đường dẫn gói tương ứng
Điều này có thể không phải lúc nào cũng được mong muốn đối với nhúng Python và do đó chúng tôi cần tùy chọn đầu tiên, JAVA_HOME
0, để kích hoạt nó. Ở đây chúng tôi cũng gặp phải một vấn đề. mô-đun maven-enforcer-plugin
9 sử dụng đường dẫn thực thi khởi chạy để xác định đường dẫn gói — nhưng chúng tôi đang khởi chạy một ứng dụng Java. Đây là những gì tùy chọn thứ hai là dành cho. chúng tôi nói với bộ thực thi Python rằng nó sẽ hoạt động như thể nó được khởi chạy từ một tệp thực thi bên trong môi trường ảo. Chúng ta lấy JAVA_HOME
2 ở đâu?
Chúng tôi có thể trực tiếp sử dụng API nhúng để nhận các phiên bản JAVA_HOME
3 từ không gian Python và tương tác với chúng. Tuy nhiên, để tách mã Java và Python, nên sử dụng giao diện Java. Bằng cách này, chúng tôi có thể dễ dàng có các phụ trợ kết xuất khác không dựa trên Python trong tương lai
Chúng tôi phải đánh giá một số mã Python, nhưng chúng tôi sẽ thiết lập nó để chúng tôi chỉ cần nhập một lớp Python triển khai giao diện JAVA_HOME
4. Sau khi chúng tôi xử lý lớp Python JAVA_HOME
5, chúng tôi khởi tạo một phiên bản của nó. Sau đó, chúng tôi có thể bọc đối tượng và hiển thị nó dưới dạng triển khai giao diện JAVA_HOME
4 và hưởng lợi từ việc gõ tĩnh hơn một chút trong quá trình phát triển
Bây giờ chúng ta đã thiết lập giao diện mà chúng ta muốn mã Java trông như thế nào, hãy bắt đầu viết một tệp Python để tải. API PyGal hơi quá thấp so với mục đích của chúng tôi. Để phù hợp với giao diện JAVA_HOME
4 mà chúng ta đã định nghĩa trong Java, chúng ta tạo một lớp Python có hàm kết xuất nhận hai tham số ngoài tham chiếu [ngầm định trong Java] cho thể hiện đối tượng
Mã nên làm gì?
Như bạn có thể thấy, chúng tôi chỉ đánh giá chuỗi mà người dùng đưa vào trường nhập liệu. Mã này không thực hiện bất kỳ kiểm tra lỗi nào, nhưng người dùng thực sự có thể đang chạy bất kỳ biểu thức Python nào ở đây, vì vậy trong một ứng dụng thực, chúng ta nên cẩn thận hơn khi xác thực đầu vào và chúng ta nên cân nhắc sử dụng các tính năng hộp cát của GraalVM để giảm thiểu khả năng của Python
Khi chúng tôi có các giá trị, chúng tôi chỉ cần gọi PyGal để hiển thị SVG. Dữ liệu SVG là một đối tượng Python JAVA_HOME
8 với mã hóa UTF-8
Vì giao diện Java yêu cầu giá trị trả về JAVA_HOME
9, chúng tôi phân lớp venv
0 trong Python và sử dụng phân lớp đó làm giá trị trả về của chúng tôi
Ở đây, venv
1 là một lớp con thích hợp của venv
0, chỉ với một số phương thức được triển khai trong Python. Vì nó không phải là một đối tượng Python mà là một đối tượng Java thích hợp, nên nó được "niêm phong", nghĩa là chúng ta không thể tự động thêm các thành viên như chúng ta có thể làm cho các đối tượng Python. Do đó, Python trên GraalVM cung cấp một thành viên venv
3 đặc biệt chỉ hiển thị từ Python, trên đó chúng tôi có thể xác định các thành viên bổ sung một cách linh hoạt. Tuy nhiên, chúng chỉ hiển thị từ mã Python;
Vậy làm cách nào để triển khai venv
1?
Một điều đáng tiếc là lớp trừu tượng InputStream có một phương thức venv
5 mà chúng ta phải định nghĩa bằng Python. Tuy nhiên, vì Python không hỗ trợ nạp chồng hàm như Java, nên phương thức venv
6 của Python sẽ không chỉ triển khai venv
7 mà còn ghi đè các triển khai InputStream mặc định cho venv
8 và venv
9. Vì vậy, việc triển khai Python của chúng tôi phải xử lý cả ba biến thể trong một phương thức. Vì chúng ta đang xử lý các byte, nên các phạm vi giá trị cũng phải được xem xét - Các byte Python không được ký trong khi các byte Java được ký. Để biết chi tiết về việc triển khai venv
1, bạn có thể tham khảo
Cuối cùng, chúng ta cần xuất JAVA_HOME
5 sang mã Java. Python không có không gian tên "toàn cầu" ngầm định; . Để xuất lớp Python vào không gian tên GraalVM Polyglot toàn cầu, chúng tôi sử dụng đoạn mã sau
Bây giờ chúng ta đã sắp xếp cách các thành phần tương tác và đã viết mã xung quanh nó, hãy chạy ứng dụng của chúng ta bằng lệnh venv
3
Ứng dụng AWT đã hoàn thành hiển thị biểu đồ PyGal
Đơn giản mà đẹp. Bạn có thể gõ venv
4 hoặc venv
5 vào trường chức năng và nhấn Return. Kết xuất đầu tiên mất vài giây trên máy của tôi và các chuỗi biên dịch khởi động để tối ưu hóa sự kết hợp độc đáo này giữa mã Java và mã Python. Các lần kết xuất tiếp theo sẽ nhanh hơn và sau khoảng 5 hoặc 6 lần kết xuất [trên máy của tôi], mỗi yêu cầu kết xuất mới chỉ mất chưa đến một giây và tải của máy giảm xuống do tất cả mã đã được biên dịch bởi GraalVM JIT
Với GraalVM Native Image, chúng tôi có một công nghệ để biên dịch mã Java trước thời hạn. Chúng tôi đang tích cực làm việc để cho phép duy trì mã Python khởi động để ứng dụng có thể chạy nhanh trong lần hiển thị đầu tiên. Chúng tôi đã có một nguyên mẫu của tính năng này và hy vọng sẽ làm sáng tỏ tính năng đó cho Python trong tương lai không xa
kết luậnNhúng Python vào các ứng dụng Java chạy trên GraalVM thật dễ dàng, nhưng việc sử dụng các gói Python đúng cách đi kèm với một số cạm bẫy mà chúng ta cần lưu ý. Với kho lưu trữ mẫu nhỏ được thảo luận trong bài viết này, bất kỳ ai cũng có thể thiết lập và chạy với nó một cách nhanh chóng và tránh được một số trở ngại và trở ngại khi khởi động. Hãy thử một lần. Chúng tôi luôn hoan nghênh phản hồi trên Github, Slack hoặc thậm chí ở đây trong các nhận xét. Từ các yêu cầu tính năng đến các vấn đề giúp chúng tôi ưu tiên các gói trong hệ sinh thái, tất cả đều là thông tin đầu vào có giá trị giúp GraalVM trở thành thời gian chạy tuyệt vời cho Java và Python