عشرة أشياء يمكنك القيام بها باستخدام GraalVM


من المترجم: GraalVM هي تقنية جديدة ومثيرة للاهتمام ، ولكن على Habré لا توجد العديد من المقالات التي يمكن أن تظهر أمثلة على قدرات Graal. المقالة أدناه ليست مجرد قائمة لما يمكن أن تفعله GraalVM ، بل هي أيضًا فئة رئيسية صغيرة مماثلة للفئة التي أجراها كريس سيتون وأوليج شيلاييف في Oracle CodeOne 2018. بعد المؤلف ، أحثك ​​على محاولة تقديم أمثلة من المقال ، إنها حقًا مثيرة للاهتمام.


هناك الكثير من الأشياء المختلفة في GraalVM ، وإذا سمعت هذا الاسم من قبل ، أو حتى رأيت تقارير ، فلا يزال هناك الكثير من الأشياء التي ربما لا تزال لا تعرف عنها ، ولكن ما GraalVM يمكنه فعلها. في هذه المقالة ، سوف نلقي نظرة على الميزات المختلفة التي يوفرها GraalVM وإظهار ما يمكنك القيام به معها.


  1. تنفيذ جافا السريع
  2. تقليل وقت البدء واستخدام الذاكرة لجافا
  3. دمج JavaScript و Java و Ruby و R
  4. تنفيذ البرامج المكتوبة بلغات النظام الأساسي
  5. أدوات مشتركة لجميع لغات البرمجة
  6. ملحق تطبيق JVM
  7. التطبيقات التابعة للنظام الأساسي
  8. كود Java كمكتبة خاصة بالنظام الأساسي
  9. دعم لغات البرمجة المتعددة في قاعدة البيانات
  10. إنشاء لغات البرمجة ل GraalVM

يمكنك القيام بكل ما هو موضح في هذه المقالة باستخدام GraalVM 1.0.0 RC1 ، والذي يتوفر عبر الرابط من موقع GraalVM . لقد استخدمت MacOS Enterprise Edition ، لكن الكود المكتوب هنا سيعمل على نظامي Linux و GraalVM Community Edition.


عندما تقرأ المقال ، قم بتشغيل البرامج الموضحة فيه! يمكن تنزيل الكود من جيثب .


التثبيت


بعد التنزيل من http://graalvm.org/downloads ، أضفت المسار إلى الملفات التنفيذية GraalVM في $PATH . بشكل افتراضي ، يضيف هذا دعمًا لتنفيذ Java و JavaScript.


 $ git clone https://github.com/chrisseaton/graalvm-ten-things.git $ cd foo $ tar -zxf graalvm-ee-1.0.0-rc1-macos-amd64.tar.gz # or graalvm-ee-1.0.0-rc1-linux-amd64.tar.gz on Linux $ export PATH=graalvm-1.0.0-rc1/Contents/Home/bin:$PATH # or PATH=graalvm-1.0.0-rc1/bin:$PATH on Linux 

يأتي GraalVM مع دعم JavaScript مدمج ويحتوي على مدير حزمة يسمى gu يضيف القدرة على تثبيت دعم للغات غير Java و JavaScript. قمت بالإضافة إلى تثبيت روبي ، بيثون و R ، يتم تنزيلها من جيثب.


 $ gu install -c org.graalvm.ruby $ gu install -c org.graalvm.python $ gu install -c org.graalvm.R 

الآن ، إذا قمت بتنفيذ الأمر java أو js ، فسترى إصدارات GraalVM من هذه المحركات.


 $ java -version java version "1.8.0_161" Java(TM) SE Runtime Environment (build 1.8.0_161-b12) GraalVM 1.0.0-rc1 (build 25.71-b01-internal-jvmci-0.42, mixed mode) $ js --version Graal JavaScript 1.0 (GraalVM 1.0.0-rc1) 

1. تنفيذ جافا السريع


"Graal" في GraalVM هو اسم المترجم. هو وحده مخلوق لحكم الجميع ! هذا يعني أن هذا تطبيق مترجم واحد مكتوب في شكل مكتبة يمكن استخدامه للعديد من الأشياء المختلفة. على سبيل المثال ، نستخدم Graal لتجميع كلٍّ من وقت مبكر وفي الوقت المناسب فقط لتجميع التعليمات البرمجية المكتوبة بلغات برمجة مختلفة ، بما في ذلك بنى المعالج المختلفة.


أول وأسهل طريقة لاستخدام Graal هي استخدامه كمترجم Java JIT.


كمثال ، سوف نستخدم برنامجًا ينتج 10 من أكثر الكلمات شيوعًا في المستند. يستخدم البرنامج قدرات لغة Java الحديثة ، مثل التدفقات والمجموعات.


 import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; public class TopTen { public static void main(String[] args) { Arrays.stream(args) .flatMap(TopTen::fileLines) .flatMap(line -> Arrays.stream(line.split("\\b"))) .map(word -> word.replaceAll("[^a-zA-Z]", "")) .filter(word -> word.length() > 0) .map(word -> word.toLowerCase()) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) .entrySet().stream() .sorted((a, b) -> -a.getValue().compareTo(b.getValue())) .limit(10) .forEach(e -> System.out.format("%s = %d%n", e.getKey(), e.getValue())); } private static Stream<String> fileLines(String path) { try { return Files.lines(Paths.get(path)); } catch (IOException e) { throw new RuntimeException(e); } } } 

يشمل GraalVM برنامج التحويل البرمجي javac ، لكن لا يوجد فرق في هذا العرض التوضيحي سواء لاستخدامه أو المترجم القياسي. لذلك ، يمكنك استخدام برنامج التحويل البرمجي javac القياسي إذا كنت تريد.


 $ javac TopTen.java 

إذا قمنا بتشغيل الأمر java ، والذي تم تضمينه في GraalVM ، فسيتم استخدام برنامج التحويل البرمجي Grait JIT تلقائيًا - لا يلزم اتخاذ خطوات إضافية. سأستخدم الأمر time أجل الحصول على بيانات حقيقية حول الوقت الذي تم إنفاقه في تنفيذ البرنامج من البداية إلى النهاية ، بدلاً من نشر علامة صغيرة معقدة. سيتم أيضًا استخدام كمية كبيرة من المدخلات بحيث لا توجد تلميحات حول الثواني المحفوظة هنا أو هناك. حجم ملف large.txt هو 150 ميغابايت.


 $ make large.txt $ time java TopTen large.txt sed = 502701 ut = 392657 in = 377651 et = 352641 id = 317627 eu = 317627 eget = 302621 vel = 300120 a = 287615 sit = 282613 real 0m17.367s user 0m32.355s sys 0m1.456s 

Graal مكتوب بلغة Java وليس C ++ ، مثل معظم برامج JIT الأخرى لجافا. نعتقد أن هذا يسمح لنا بتحسينه بشكل أسرع من المترجمين الحاليين ، بإضافة تحسينات قوية جديدة (مثل ، على سبيل المثال ، تحليل الهروب الجزئي) غير متوفرة في برنامج التحويل البرمجي JIT القياسي لـ HotSpot.
وهذا يمكن أن يجعل برامج جافا أسرع بكثير.


لأغراض المقارنة ، لتشغيل البرامج بدون برنامج التحويل البرمجي Grait JIT ، -XX:-UseJVMCICompiler . JVMCI هي الواجهة بين Graal و JVM. يمكنك أيضًا تشغيل المثال على JVM قياسي ومقارنة النتائج.


 $ time java -XX:-UseJVMCICompiler TopTen large.txt sed = 502701 ut = 392657 in = 377651 et = 352641 id = 317627 eu = 317627 eget = 302621 vel = 300120 a = 287615 sit = 282613 real 0m23.511s user 0m24.293s sys 0m0.579s 

يوضح هذا الاختبار أن Graal تدير برنامج Java الخاص بنا في حوالي ثلاثة أرباع الوقت الذي يستغرقه لتشغيله باستخدام برنامج التحويل البرمجي HotSpot القياسي. حيث نعتقد أن تحسين الإنتاجية حسب وحدات النسبة المئوية يعد إنجازًا كبيرًا ، فإن 25٪ يعد أمرًا كبيرًا.


Twitter هي الشركة الوحيدة التي تستخدم Graal على خوادم "battle" ، وهم يقولون إنها مبررة لهم ، من حيث توفير الأموال الحقيقية. يستخدم Twitter Graal لتنفيذ التطبيقات المكتوبة في Scala - Graal يعمل على مستوى JVM في bytecode ، أي ينطبق على أي لغة JVM.


هذه هي أول حالة استخدام لـ GraalVM - ما عليك سوى استبدال برنامج التحويل البرمجي JIT بإصدار أفضل لتطبيقات Java الحالية.


2. تقليل وقت البدء واستخدام الذاكرة لجافا


تتضح نقاط القوة في نظام Java الأساسي بشكل خاص عند العمل مع العمليات الطويلة الأمد والأحمال القصوى. وعلى النقيض من ذلك ، تعاني العمليات القصيرة العمر من أوقات بدء تشغيل طويلة واستخدام عالي نسبياً للذاكرة.


على سبيل المثال ، إذا قمنا بتشغيل التطبيق من القسم السابق ، وقمنا بتزويده بكمية أقل بكثير من بيانات الإدخال - حوالي 1 كيلو بايت بدلاً من 150 ميجابايت ، فيبدو أن الأمر سيستغرق وقتًا طويلاً بشكل غير معقول وكثير من الذاكرة - حوالي 60 ميغابايت ، لمعالجة هذا الملف الصغير . نستخدم خيار -l لطباعة مقدار الذاكرة المستخدم بالإضافة إلى وقت التنفيذ.


 $ make small.txt $ /usr/bin/time -l java TopTen small.txt # -v on Linux instead of -l sed = 6 sit = 6 amet = 6 mauris = 3 volutpat = 3 vitae = 3 dolor = 3 libero = 3 tempor = 2 suscipit = 2 0.32 real 0.49 user 0.05 sys 59846656 maximum resident set size 

يوفر لنا GraalVM أداة لحل هذه المشكلة. قلنا أن Graal هي مكتبة مترجم ويمكن استخدامها بعدة طرق مختلفة. واحد منهم هو تجميع مقدما في صورة قابلة للتنفيذ على النظام الأساسي ، بدلا من تجميع في الوقت المناسب فقط في وقت التشغيل. هذا مشابه لكيفية عمل برنامج التحويل البرمجي العادي ، مثل gcc .


 $ native-image --no-server TopTen classlist: 1,513.82 ms (cap): 2,333.95 ms setup: 3,584.09 ms (typeflow): 4,642.13 ms (objects): 3,073.58 ms (features): 156.34 ms analysis: 8,059.94 ms universe: 353.02 ms (parse): 1,277.02 ms (inline): 1,412.08 ms (compile): 10,337.76 ms compile: 13,776.23 ms image: 2,526.63 ms write: 1,525.03 ms [total]: 31,439.47 ms 

يقوم هذا الأمر بإنشاء ملف topten الأساسي يسمى topten . لا يبدأ هذا الملف في JVM ، ولا يرتبط بـ JVM ، ولا يشمل JVM بأي طريقة. يقوم أمر native-image بالفعل بتجميع كود Java الخاص بك ومكتبات Java التي تستخدمها في كود الآلة بالكامل. بالنسبة لمكونات وقت التشغيل مثل أداة تجميع مجمعي البيانات المهملة ، نطلق جهاز VM الجديد الخاص بنا يسمى SubstrateVM ، والذي ، مثل Graal ، مكتوب بلغة Java أيضًا.


إذا نظرت إلى التبعيات التي تستخدمها ، سترى أن هذه مكتبات النظام القياسية فقط. يمكننا نقل ملف واحد فقط إلى نظام لم يتم فيه تثبيت JVM على الإطلاق وتشغيله هناك للتحقق من أنه لا يستخدم JVM أو أي ملفات أخرى. Topten أيضًا صغير جدًا - يستغرق الرمز القابل للتنفيذ أقل من 6 ميغابايت.


 $ otool -L topten # ldd topten on Linux topten: .../CoreFoundation.framework ... .../libz.1.dylib ... .../libSystem.B.dylib ... $ du -h topten 5.7M topten 

إذا قمنا بتشغيل هذا الملف القابل للتنفيذ ، فسوف نرى أنه يبدأ بترتيب من حيث الحجم بشكل أسرع ويستخدم حول ترتيب بحجم ذاكرة أقل من نفس البرنامج الذي يعمل تحت JVM. يكون الإطلاق سريعًا لدرجة أنك لن تلاحظ المدة التي استغرقتها. إذا كنت تستخدم سطر الأوامر ، فلن تشعر بالإيقاف المؤقت الموجود عادة عند تشغيل برنامج صغير قصير العمر ضمن JVM


 $ /usr/bin/time -l ./topten small.txt sed = 6 sit = 6 amet = 6 mauris = 3 volutpat = 3 vitae = 3 dolor = 3 libero = 3 tempor = 2 suscipit = 2 0.02 real 0.00 user 0.00 sys 4702208 maximum resident set size 

الأداة المساعدة native-image بها بعض القيود . لذلك ، في وقت الترجمة يجب أن يكون لديك جميع الفئات ، هناك أيضًا قيود على استخدام Reflection API. ولكن هناك بعض المزايا الإضافية على التحويل البرمجي الأساسي ، مثل تنفيذ أدوات التهيئة الثابتة في وقت الترجمة. وبالتالي ، يتم تقليل مقدار العمل المنجز في كل مرة يتم فيها تنزيل التطبيق.


هذا هو التطبيق الثاني لـ GraalVM - توزيع وتنفيذ برامج Java الحالية ، مع بداية سريعة وتقليل استهلاك الذاكرة. تعمل هذه الطريقة على إصلاح مشكلات التكوين مثل العثور على الجرة المناسبة في وقت التشغيل ، كما تتيح لك إنشاء صور أصغر لرسو السفن.


3. الجمع بين JavaScript و Java و Ruby و R


إلى جانب Java ، تتضمن GraalVM تطبيقات جديدة لمحركات JavaScript و Ruby و R و Python. مكتوبة باستخدام إطار جديد يسمى الكمأة . هذا الإطار يجعل من الممكن إنشاء مترجمين للغة بسيطة وعالية الأداء. عندما تكتب مترجم لغة باستخدام Truffle ، فسيستخدم تلقائيًا Graal لتوفير ترجمة JIT للغتك. وبالتالي ، فإن Graal ليس فقط مترجم JIT ومترجم AOT لجافا ، بل يمكن أيضًا أن يكون مترجم JIT لجافا سكريبت ، روبي ، آر وبيثون.


يهدف دعم لغات الأطراف الثالثة في GraalVM إلى أن يكون بديلاً شفافًا للمحركات الحالية لتنفيذ لغات مختلفة. على سبيل المثال ، يمكننا تثبيت الوحدة النمطية "color" لـ Node.js:


 $ npm install --global color ... + color@3.0.0 added 6 packages in 14.156s 

ثم اكتب برنامجًا باستخدام هذه الوحدة لتحويل ألوان RGB HTML إلى HSL:


 var Color = require('color'); process.argv.slice(2).forEach(function (val) { print(Color(val).hsl().string()); }); 

وتشغيله بالطريقة المعتادة:


 $ node color.js '#42aaf4' hsl(204.89999999999998, 89%, 60.8%) 

تعمل محركات التنفيذ الخاصة بلغات مختلفة في GraalVM معًا - هناك واجهة برمجة تطبيقات تسمح لك بتشغيل التعليمات البرمجية من لغة واحدة في برنامج مكتوب بلغة أخرى. ويتيح لك ذلك كتابة برامج متعددة اللغات - برامج مكتوبة بأكثر من لغة برمجة واحدة.


قد يكون ذلك ضروريًا إذا كتبت معظم برنامجك بلغة واحدة ، ولكنك ترغب في استخدام مكتبة مكتوبة بلغة برمجة أخرى. على سبيل المثال ، افترض أننا بحاجة إلى كتابة تطبيق لتحويل اسم لون من CSS إلى تمثيله الرقمي في Node.js ، لكننا نريد استخدام مكتبة ألوان Ruby بدلاً من كتابة التحويل بأنفسنا.


 var express = require('express'); var app = express(); color_rgb = Polyglot.eval('ruby', ` require 'color' Color::RGB `); app.get('/css/:name', function (req, res) { color = color_rgb.by_name(req.params.name).html() res.send('<h1 style="color: ' + color + '" >' + color + '</h1>'); }); app.listen(8080, function () { console.log('serving at http://localhost:8080') }); 

في هذا الرمز ، كتبنا أننا نحتاج إلى تنفيذ كود Ruby كسلسلة ، لكن لاحظ أننا لم نفعل الكثير هنا - لقد قمنا فقط بتوصيل المكتبات ثم أعدنا كائن Ruby. في روبي ، نستخدمها كما يلي: Color::RGB.by_name (name).html . إذا نظرت إلى كيفية استخدام color_rgb لاحقًا في جافا سكريبت ، فسترى أننا نسميها بالفعل نفس الأساليب من JavaScript ، على الرغم من أنها كائنات وطرق Ruby. ونقوم بتمريرها على هيئة سلاسل جافا سكريبت ونجمع النتيجة ، وهي سلسلة روبي ، بسلسلة جافا سكريبت.


تثبيت كل التبعيات - روبي وجافا سكريبت.


 $ gem install color Fetching: color-1.8.gem (100%) Successfully installed color-1.8 1 gem installed $ npm install express + express@4.16.2 updated 1 package in 10.393s 

بعد ذلك ، يجب أن تبدأ node بخيارين إضافيين: --polyglot ، لنقول إننا بحاجة إلى الوصول إلى لغات أخرى و - --jvm ، لأن صورة node القابلة للتنفيذ بشكل افتراضي لا تتضمن أي شيء آخر غير JavaScript.


 $ node --polyglot --jvm color-server.js serving at http://localhost:8080 

ثم انتقل إلى عنوان URL http: // localhost: 8080 / css / orange (أو بعض الألوان الأخرى) ، كالمعتاد ، في متصفحك.

دعونا نحاول تقديم مثال أكثر جدية ، والذي يستخدم المزيد من اللغات والوحدات النمطية.


جافا سكريبت لا يدعم أعدادا كبيرة جدا. لقد وجدت عدة وحدات مثل عدد صحيح كبير ، لكنها كلها غير فعالة ل تخزين مكونات الرقم كأرقام JavaScript العائمة. فئة BigInteger في Java أكثر فعالية ، دعنا نستخدمها للقيام ببعض العمليات الحسابية مع أعداد صحيحة كبيرة.


لا يحتوي JavaScript أيضًا على دعم مضمن لرسم الرسومات ، بينما يرسم R الرسومات بشكل ممتاز. دعنا نستخدم وحدة svg من R لرسم مخطط مبعثر لوظيفة مثلثية في الفضاء ثلاثي الأبعاد.


في كلتا الحالتين ، سوف نستخدم API لدعم تعدد اللغات من GraalVM (المشار إليها فيما يلي باسم Polyglot API) ويمكننا ببساطة إدراج نتائج تنفيذ البرامج بلغات أخرى في JavaScript.


 const express = require('express') const app = express() const BigInteger = Java.type('java.math.BigInteger') app.get('/', function (req, res) { var text = 'Hello World from Graal.js!<br> ' // Using Java standard library classes text += BigInteger.valueOf(10).pow(100) .add(BigInteger.valueOf(43)).toString() + '<br>' // Using R interoperability to create graphs text += Polyglot.eval('R', `svg(); require(lattice); x <- 1:100 y <- sin(x/10) z <- cos(x^1.3/(runif(1)*5+10)) print(cloud(x~y*z, main="cloud plot")) grDevices:::svg.off() `); res.send(text) }) app.listen(3000, function () { console.log('Example app listening on port 3000!') }) 

افتح http: // localhost: 3000 / في متصفحك لرؤية النتيجة:

هذا هو الشيء الثالث الذي يمكننا القيام به مع البرامج التي تديرها GraalVM المكتوبة بعدة لغات واستخدام الوحدات النمطية من هذه اللغات معًا في برنامج واحد. نقدم هذا كوسيلة لتوحيد بيئات وقت التشغيل والمكتبات - يمكنك استخدام لغة البرمجة التي تعتقد أنها الأنسب لحل المهمة الحالية وأي مكتبة تريدها ، بصرف النظر عن لغة البرمجة المكتوبة بها.


4. تنفيذ البرامج المكتوبة بلغات النظام الأساسي


لغة أخرى يدعمها GraalVM هي C. GraalVM يمكنه تنفيذ كود C بنفس الطريقة التي ينفذ بها البرامج المكتوبة بلغة JavaScript و Ruby.


ما تدعمه GraalVM فعليًا هو تنفيذ التعليمات البرمجية الناتجة عن تنفيذ الأدوات المساعدة LLVM ، أي إن هذا يعني أنه يمكنك استخدام الأدوات الحالية للغة C والأخرى التي تدعم LLVM ، مثل C ++ و Fortran ، وربما مزيد من اللغات في المستقبل. من أجل بساطة التوضيح ، أقوم بتشغيل إصدار خاص من gzip ، يتم تجميعه في ملف واحد (يدعم ستيفن مكامانت هذا الإصدار). هذا هو مجرد شفرة المصدر gzip وتكوين autoconf مدمجة في ملف واحد للبساطة. اضطررت إلى تصحيح بعض الأشياء لجعلها تعمل على نظام macOS و clang ، لكنني لم أفعل شيئًا على وجه التحديد لدعم GraalVM.


نحن نجمع gzip باستخدام clang المعياري (مترجم LLVM لـ C) ونريده أن يجعلنا رمزًا بتشفير LLVM ، وليس بناءًا خاصًا بالنظام الأساسي ، لأن GraalVM لن يطلقه. أنا أستخدم clang 4.0.1.


 $ clang -c -emit-llvm gzip.c 

ثم قم بتشغيل النتيجة ، مباشرة باستخدام الأمر lli (مترجم الباركود LLVM) من GraalVM. دعونا نحاول ضغط الملف باستخدام أرشيف نظام gzip ، ثم فك ضغطه باستخدام gzip الذي يعمل تحت GraalVM.


 $ cat small.txt Lorem ipsum dolor sit amet... $ gzip small.txt $ lli gzip.bc -d small.txt.gz $ cat small.txt Lorem ipsum dolor sit amet... 

تستخدم تطبيقات Ruby و Python في GraalVM نفس الأسلوب لتشغيل ملحقات مكتوبة بلغة C لهذه اللغات. هذا يعني أنه يمكنك تشغيل هذه الملحقات داخل VM وهذا يسمح لنا بالحفاظ على سرعة تنفيذ عالية حتى لو استخدمنا واجهات تمديد قديمة خاصة بالنظام الأساسي.


هذه هي الطريقة الرابعة لاستخدام GraalVM - تشغيل البرامج المكتوبة بلغات خاصة بالنظام الأساسي ، مثل C أو C ++ ، بالإضافة إلى تشغيل ملحقات إلى لغات مثل Python أو Ruby ، ​​والتي لا يمكنها إجراء تطبيقات JVM لهذه اللغات ، مثل JRuby.


5. أدوات عامة لجميع لغات البرمجة


إذا قمت بالبرمجة في Java ، فمن المحتمل أنك تستخدم أدوات عالية الجودة مثل IDEs و debuggers و profilers. لا تحتوي جميع اللغات على مجموعة الأدوات هذه ، ولكن يمكنك الحصول عليها إذا كنت تستخدم لغات مدعومة بواسطة GraalVM.


يتم تطبيق دعم جميع اللغات في GraalVM (باستثناء Java ، في الوقت الحالي) باستخدام إطار عمل مشترك - Truffle. يتيح لنا ذلك جعل الوظيفة ، على سبيل المثال ، مصحح الأخطاء ، مرة واحدة واستخدامها لجميع اللغات.


لتجربة ذلك ، سنكتب أبسط برنامج - FizzBuzz ، لأنه مرئي (يطبع شيئًا ما على الشاشة) وله فروع واضحة تستخدم فقط في بعض التكرارات. وبالتالي ، سيكون من الأسهل بالنسبة لنا تعيين نقاط توقف. لنبدأ بتنفيذ جافا سكريبت.


 function fizzbuzz(n) { if ((n % 3 == 0) && (n % 5 == 0)) { return 'FizzBuzz'; } else if (n % 3 == 0) { return 'Fizz'; } else if (n % 5 == 0) { return 'Buzz'; } else { return n; } } for (var n = 1; n <= 20; n++) { print(fizzbuzz(n)); } 

نبدأ تشغيل البرنامج كالمعتاد باستخدام الأداة المساعدة js ضمن GraalVM.


 $ js fizzbuzz.js 1 2 Fizz 4 Buzz Fizz 

يمكننا أيضا تشغيل البرنامج مع العلم - --inspect . سيعطينا هذا رابطًا يمكنك فتحه في Chrome وإيقاف البرنامج في مصحح الأخطاء.


 $ js --inspect fizzbuzz.js Debugger listening on port 9229. To start debugging, open the following URL in Chrome: chrome-devtools://devtools/bundled/inspector.html?ws=127.0.0.1:9229/6c478d4e-1350b196b409 

يمكنك تعيين نقطة توقف في رمز FizzBuzz ثم متابعة التنفيذ. عند مقاطعة البرنامج للتنفيذ ، سنرى قيمة المتغير n في المصحح ويمكننا متابعة تنفيذ البرنامج أو دراسة واجهة المصحح.

عادةً ما يتم استخدام مصحح الأخطاء في Chrome لجافا سكريبت ، لكن بالنسبة إلى GraalVM في JavaScript لا يوجد شيء مختلف عن اللغات الأخرى. --inspect العلامة --inspect أيضًا وتعمل في تطبيقات Python و Ruby و R. لن أريك مصدر كل برنامج ، لكنها تعمل بنفس الطريقة وستحصل على نفس مصحح الأخطاء في Chrome لكل منها.


 $ graalpython --jvm --inspect fizzbuzz.py 


 $ ruby --inspect fizzbuzz.rb 


 $ Rscript --inspect fizzbuzz.r 


أداة أخرى قد تكون معتادًا عليها من Java هي VisualVM. يوفر واجهة مستخدم يمكنك من خلالها الانضمام إلى JVM قيد التشغيل على جهازك المحلي أو من خلال شبكة لفحص الجوانب المختلفة لتنفيذ البرنامج ، مثل استخدام الذاكرة أو تنفيذ سلسلة الرسائل.


يتضمن GraalVM VisualVM كأداة مساعدة jvisualvm قياسية.


 $ jvisualvm &> /dev/null & 

إذا قمنا بتشغيل VisualVM أثناء تشغيل برنامج TopTen Java ، فيمكننا ملاحظة استخدام الذاكرة أو ، على سبيل المثال ، أخذ لقطة من محتويات الذاكرة ومعرفة أنواع الكائنات التي نستخدمها في الذاكرة على الكومة.


 $ java TopTen large.txt 


كتبت هذا البرنامج في روبي لتوليد بعض القمامة في الذاكرة في وقت التشغيل.


 require 'erb' x = 42 template = ERB.new <<-EOF The value of x is: <%= x %> EOF loop do puts template.result(binding) end 

إذا قمت بتشغيل تطبيق Ruby القياسي على JVM - JRuby ، ​​فسوف تشعر بخيبة أمل إزاء VisualVM لأنك سترى فقط كائنات Java الداخلية بدلاً من الكائنات بلغتك.


إذا كنت تستخدم إصدار Ruby لـ GraalVM ، فسيتعرف VisualVM على كائنات Ruby. نحن بحاجة إلى استخدام الخيار - jvm لاستخدام VisualVM ، مثل أنها لا تدعم الإصدارات الأصلية من روبي.


 $ ruby --jvm render.rb 

, , Java , , , Summary, Ruby Heap Ruby .

Truffle — - Nexus . Truffle , , API Truffle' , , Truffle, .


, GraalVM — , . Truffle GraalVM , VisualVM.


6. JVM


, , , Java . API org.graalvm.polyglot , .


 import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; public class ExtendJava { public static void main(String[] args) { String language = "js"; try (Context context = Context.newBuilder().allowNativeAccess(true).build()) { for (String arg: args) { if (arg.startsWith("-")) { language = arg.substring(1); } else { Value v = context.eval(language, arg); System.out.println(v); } } } } } 

javac java GraalVM, org.graalvm.* classpath , .. .


 $ javac ExtendJava.java $ java ExtendJava '14 + 2' 16 $ java ExtendJava -js 'Math.sqrt(14)' 3.7416573867739413 $ java ExtendJava -python '[2**n for n in range(0, 8)]' [1, 2, 4, 8, 16, 32, 64, 128] $ java ExtendJava -ruby '[4, 2, 3].sort' [2, 3, 4] 

, — , node ruby , GraalVM.


GraalVM — Java . Polyglot API “” Java , .


7. -


GraalVM , , — , , GraalVM, - . , JavaScript , V8, Python — CPython , .. . GraalVM — Polyglot .


GraalVM, , JavaScript. Polyglot , , :


 $ graalvm-1.0.0-rc1/Contents/Home/jre/lib/svm/bin/rebuild-images libpolyglot 

C, , , GraalVM, . ExtendJava , , .


 #include <stdlib.h> #include <stdio.h> #include <polyglot_api.h> int main(int argc, char **argv) { graal_isolate_t *isolate = NULL; graal_isolatethread_t *thread = NULL; if (graal_create_isolate(NULL, &isolate) != 0 || (thread = graal_current_thread(isolate)) == NULL) { fprintf(stderr, "initialization error\n"); return 1; } poly_context context = NULL; if (poly_create_context(thread, NULL, 0, &context) != poly_ok) { fprintf(stderr, "initialization error\n"); return 1; } char* language = "js"; for (int n = 1; n < argc; n++) { if (argv[n][0] == '-') { language = &argv[n][1]; } else { poly_value result = NULL; if (poly_context_eval(thread, context, language, "unicalc", argv[n], &result) != poly_ok) { fprintf(stderr, "eval error\n"); return 1; } char buffer[1024]; size_t length; if (poly_value_to_string_utf8(thread, result, buffer, sizeof(buffer), &length) != poly_ok) { fprintf(stderr, "to string error\n"); return 1; } buffer[length] = '\0'; printf("%s\n", buffer); poly_destroy_handle(thread, result); } } return 0; } 

, polyglot GraalVM. , , JVM.


 $ clang -Igraalvm-1.0.0-rc1/Contents/Home/jre/lib/polyglot / -rpath graalvm-1.0.0-rc1/Contents/Home / -Lgraalvm-1.0.0-rc1/Contents/Home/jre/lib/polyglot / -lpolyglot extendc.c -o extendc $ otool -L extendc extendc: .../libpolyglot.dylib ... .../libSystem.B.dylib ... 

 $ ./extendc '14 + 2' 16 $ ./extendc -js 'Math.sqrt(14)' 3.7416573867739413 $ ./extendc -python '[2**n for n in range(0, 8)]' [1, 2, 4, 8, 16, 32, 64, 128] 

, GraalVM — - , , GraalVM.


8. Java -


Java , , , , - , . Java - , JVM , .


GraalVM Java , , - , . , , Java JVM.


, Apache SIS , ( ) . SIS 0.8, http://sis.apache.org/ jar.


 import org.apache.sis.distance.DistanceUtils; public class Distance { public static void main(String[] args) { final double aLat = Double.parseDouble(args[0]); final double aLong = Double.parseDouble(args[1]); final double bLat = Double.parseDouble(args[2]); final double bLong = Double.parseDouble(args[3]); System.out.printf("%.2f km%n", DistanceUtils.getHaversineDistance(aLat, aLong, bLat, bLong)); } public static double distance(IsolateThread thread, double aLat, double aLong, double bLat, double bLong) { return DistanceUtils.getHaversineDistance(aLat, aLong, bLat, bLong); } } 

, -


 $ javac -cp sis.jar -parameters Distance.java $ java -cp sis.jar:. Distance 51.507222 -0.1275 40.7127 -74.0059 5570.25 km 

, topten .


 $ native-image --no-server -cp sis.jar:. Distance ... $ ./distance 51.507222 -0.1275 40.7127 -74.0059 5570.25 km 

, . , @CEntryPoint


 ... import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.c.function.CEntryPoint; public class Distance { ... @CEntryPoint(name = "distance") public static double distance(IsolateThread thread, double a_lat, double a_long, double b_lat, double b_long) { return DistanceUtils.getHaversineDistance(a_lat, a_long, b_lat, b_long); } ... } 

javac , GraalVM API classpath . C .


 $ native-image --no-server -cp sis.jar:. -H:Kind=SHARED_LIBRARY \ -H:Name=libdistance $ otool -L libdistance.dylib # .so on Linux libdistance.dylib: .../libdistance.dylib ... .../CoreFoundation.framework ... .../libz.1.dylib ... .../libSystem.B.dylib ... $ du -h libdistance.dylib 4.8M libdistance.dylib 

, . , : VM , , .


 #include <stdlib.h> #include <stdio.h> #include <libdistance.h> int main(int argc, char **argv) { graal_isolate_t *isolate = NULL; graal_isolatethread_t *thread = NULL; if (graal_create_isolate(NULL, &isolate) != 0 || (thread = graal_current_thread(isolate)) == NULL) { fprintf(stderr, "initialization error\n"); return 1; } double a_lat = strtod(argv[1], NULL); double a_long = strtod(argv[2], NULL); double b_lat = strtod(argv[3], NULL); double b_long = strtod(argv[4], NULL); printf("%.2f km\n", distance(thread, a_lat, a_long, b_lat, b_long)); return 0; } 

, ( LD_LIBRARY_PARTH=. Linux)


 $ clang -I. -L. -ldistance distance.c -o distance $ otool -L distance distance: .../libdistance.dylib ... .../libSystem.B.dylib ... $ ./distance 51.507222 -0.1275 40.7127 -74.0059 5570.25 km 

GraalVM — java - , JVM


9.


Polyglot — Oracle. Oracle Database Multilingual Engine (MLE), GraalVM SQL.


, front-end, JavaScript email , JavaScript validator . - , SQL PL/SQL. , .


MLE Docker :


https://oracle.imtqy.com/oracle-db-mle/releases/0.2.7/docker/


Docker Daemon.


 $ docker load --input mle-docker-0.2.7.tar.gz 

, Docker, , ( ), Bash .


 $ docker run mle-docker-0.2.7 $ docker ps $ docker exec -ti <container_id> bash -li 

sqlplus ( SQL ), Bash, , , .


 $ sqlplus scott/tiger@localhost:1521/ORCLCDB 

, sqlplus . , Bash Docker, dbjs , . sqlplus .


 $ npm install validator $ npm install @types/validator $ dbjs deploy -u scott -p tiger -c localhost:1521/ORCLCDB validator $ sqlplus scott/tiger@localhost:1521/ORCLCDB 

validator SQL .


 SQL> select validator.isEmail('hello.world@oracle.com') from dual; VALIDATOR.ISEMAIL('HELLO.WORLD@ORACLE.COM') ------------------------------------------- 1 SQL> select validator.isEmail('hello.world') from dual; VALIDATOR.ISEMAIL('HELLO.WORLD') -------------------------------- 0 

, GraalVM — , GraalVM, Oracle. , front-end back-end, , , .


10. GraalVM


Oracle Labs JavaScript, R, Ruby, Python C , Truffle, GraalVM.


Truffle — java , (AST). AST — , , , , , . , , Truffle Graal JIT , AST .


Truffle, GraalVM , , DSL. Truffle Graal , , Truffle — GraalVM. , , , , . , , . Oracle labs Ruby , , .


, , , SimpleLanguage — Truffle, JavaScript. , , , , , if .


, Truffle Oracle Labs, SmallTalk , Newspeak Lisp . Lisp , .


الخاتمة


GraalVM — , , . , , , , .


GraalVM, http://www.graalvm.org/ . , , .


, , . , GraalVM @ChrisGSeaton @shelajev .


: Oleg Šelajev , Olya Gupalo Doug Simon

Source: https://habr.com/ru/post/ar433432/


All Articles