Java có thể tương tác với python không?

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 Python

Mẫ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
GraalVM làm cho nó có thể

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 Python

Việ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-plugin3 đơn giản sẽ cài đặt các gói Python cần thiết

gói chúng lên

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 Python

Hàm maven-enforcer-plugin4 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ị

Tạo bối cảnh Python

Đ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-plugin5

Hãy đi qua điều này. Đầu tiên, chúng tôi tạo một maven-enforcer-plugin6 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-plugin7 đ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-plugin8. Mô-đun maven-enforcer-plugin9 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_HOME0, để kích hoạt nó. Ở đây chúng tôi cũng gặp phải một vấn đề. mô-đun maven-enforcer-plugin9 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_HOME2 ở đâu?

Chuẩn bị Mã Java

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_HOME3 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_HOME4. Sau khi chúng tôi xử lý lớp Python JAVA_HOME5, 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_HOME4 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

Chuẩn bị mã Python

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_HOME4 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_HOME8 với mã hóa UTF-8

Vì giao diện Java yêu cầu giá trị trả về JAVA_HOME9, chúng tôi phân lớp venv0 trong Python và sử dụng phân lớp đó làm giá trị trả về của chúng tôi

Ở đây, venv1 là một lớp con thích hợp của venv0, 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 venv3 đặ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 venv1?

Một điều đáng tiếc là lớp trừu tượng InputStream có một phương thức venv5 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 venv6 của Python sẽ không chỉ triển khai venv7 mà còn ghi đè các triển khai InputStream mặc định cho venv8 và venv9. 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 venv1, bạn có thể tham khảo

Cuối cùng, chúng ta cần xuất JAVA_HOME5 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

Cắm vào

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 venv3

Ứng dụng AWT đã hoàn thành hiển thị biểu đồ PyGal

Đơn giản mà đẹp. Bạn có thể gõ venv4 hoặc venv5 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ận

Nhú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

Java có thể nói chuyện với Python không?

Có một triển khai Python cho nền tảng Java có tên là Jython . Nó chạy trong JVM và có khả năng tương tác trực tiếp giữa Java và Python. Tương tự như vậy, có một phiên bản tên là IronPython chạy trên. nền tảng NET.

Làm cách nào để kết nối Java với Python?

Cách ưa thích của tôi để tích hợp cả hai sẽ sử dụng RPC. .
Tạo giao diện SWIG cho tất cả các lệnh gọi phương thức từ Java đến C++
Tạo mã C/C++ sẽ nhận cuộc gọi của bạn và gọi nội bộ trình thông dịch python với thông số phù hợp
Chuyển đổi phản hồi bạn nhận được từ python và gửi nó qua swig trở lại mã Java của bạn

Chủ Đề