WebAssembly (wasm) هو تنسيق تعليمات ثنائي محمول. يمكن تنفيذ نفس رمز wasm code في أي بيئة. لدعم هذا البيان ، يجب أن تكون كل لغة ونظام أساسي ونظام قادرًا على تنفيذ هذه التعليمات البرمجية ، مما يجعلها سريعة وآمنة قدر الإمكان.
Wasmer هو وقت تشغيل wasm مكتوب في
Rust . من الواضح ، يمكن استخدام wasmer في أي تطبيق Rust. يقول مؤلف المادة ، التي نُنشر ترجمتها اليوم ، إنه هو والمشاركون الآخرون في مشروع Wasmer نفذوا بنجاح وقت تشغيل رمز wasm بلغات أخرى:
هنا سنتحدث عن مشروع جديد -
go-ext-wasm ، وهي مكتبة لـ Go ، مصممة لتنفيذ كود wasm الثنائي. كما اتضح ، فإن مشروع go-ext-wasm أسرع بكثير من الحلول المماثلة الأخرى. لكن دعونا لا نتقدم على أنفسنا. لنبدأ بقصة حول كيفية العمل معه.
استدعاء وظائف wasm من Go
للبدء ، قم بتثبيت وحدة الغسل في بيئة Go (بدعم cgo).
export CGO_ENABLED=1; export CC=gcc; go install github.com/wasmerio/go-ext-wasm/wasmer
مشروع
go-ext-wasm هو مكتبة Go عادية. عند العمل مع هذه المكتبة ،
import "github.com/wasmerio/go-ext-wasm/wasmer"
إنشاء
import "github.com/wasmerio/go-ext-wasm/wasmer"
.
الآن دعنا نذهب إلى الممارسة. سوف نكتب برنامجًا بسيطًا يجمع برنامج wasm. سنستخدم لهذا ، على سبيل المثال ، الصدأ:
#[no_mangle] pub extern fn sum(x: i32, y: i32) -> i32 { x + y }
نسمي الملف باستخدام البرنامج
simple.rs
، ونتيجة لتجميع هذا البرنامج نحصل على الملف
simple.wasm .
البرنامج التالي ، المكتوب في Go ، ينفذ دالة
sum
من ملف wasm ، ويمررها بالرقمين 5 و 37 كوسيطتين:
package main import ( "fmt" wasm "github.com/wasmerio/go-ext-wasm/wasmer" ) func main() {
هنا ، يستدعي برنامج مكتوب في Go وظيفة من ملف wasm تم الحصول عليه عن طريق ترجمة التعليمات البرمجية المكتوبة في Rust.
لذلك ، نجحت التجربة ، لقد نجحنا في تنفيذ كود WebAssembly في Go. تجدر الإشارة إلى أن تحويل نوع البيانات هو الآلي. يتم نقل قيم Go التي يتم تمريرها إلى رمز wasm إلى أنواع WebAssembly. ما ترجع وظيفة wasm يتم تحويله إلى أنواع Go. نتيجة لذلك ، يبدو العمل مع وظائف من ملفات wasm في Go هو نفسه العمل مع وظائف Go العادية.
استدعاء وظائف الذهاب من رمز WebAssembly
كما رأينا في المثال السابق ، فإن وحدات WebAssembly قادرة على تصدير الوظائف التي يمكن استدعاؤها من الخارج. هذه هي الآلية التي تسمح بتنفيذ كود wasm في بيئات مختلفة.
في الوقت نفسه ، يمكن أن تعمل وحدات WebAssembly نفسها مع الوظائف المستوردة. النظر في البرنامج التالي مكتوب في الصدأ.
extern { fn sum(x: i32, y: i32) -> i32; } #[no_mangle] pub extern fn add1(x: i32, y: i32) -> i32 { unsafe { sum(x, y) } + 1 }
اسم الملف معها
import.rs
. سيؤدي تجميعها في WebAssembly إلى رمز يمكن العثور عليه
هنا .
add1
دالة
add1
المصدرة دالة
sum
. لا يوجد أي تنفيذ لهذه الوظيفة ، يتم تحديد توقيعها فقط في الملف. هذه هي الوظيفة الخارجية المزعومة. بالنسبة إلى WebAssembly ، هذه دالة مستوردة. يجب أن يتم استيراد تنفيذه.
نحن ننفذ الدالة
sum
باستخدام Go. لهذا نحن بحاجة إلى استخدام
cgo . هنا هو رمز الناتجة. يتم ترقيم بعض التعليقات ، وهي وصف لشظايا الكود الرئيسي. أدناه سنتحدث عنهم بمزيد من التفاصيل.
package main
دعونا تحليل هذا الرمز:
- يتم تعريف توقيع الدالة
sum
في C (راجع التعليق على أمر import "C"
). - يتم تعريف تنفيذ الدالة
sum
في Go (لاحظ السطر //export
- يستخدم cgo الآلية لإنشاء اتصال الكود المكتوب في Go مع الكود المكتوب في C). NewImports
هو واجهة برمجة تطبيقات تستخدم لإنشاء واردات WebAssembly. في هذا الرمز ، "sum"
هو اسم الوظيفة التي يستوردها WebAssembly ، sum
هو المؤشر إلى الدالة Go ، و C.sum
هو مؤشر الدالة C.sum
.- وأخيرًا ،
NewInstanceWithImports
عبارة عن مُنشئ مصمم لتهيئة وحدة WebAssembly باستخدام عمليات الاستيراد.
قراءة البيانات من الذاكرة
يحتوي مثيل WebAssembly على ذاكرة خطية. دعونا نتحدث عن كيفية قراءة البيانات منه. لنبدأ ، كالعادة ، برمز Rust ، الذي
memory.rs
عليه
memory.rs
.
#[no_mangle] pub extern fn return_hello() -> *const u8 { b"Hello, World!\0".as_ptr() }
نتيجة ترجمة هذا الرمز موجودة في ملف
memory.wasm
، المستخدم أدناه.
ترجع الدالة
return_hello
مؤشرًا إلى سلسلة. ينتهي السطر ، كما هو الحال في C ، بحرف فارغ.
اذهب الآن إلى جانب الذهاب:
bytes, _ := wasm.ReadBytes("memory.wasm") instance, _ := wasm.NewInstance(bytes) defer instance.Close()
تقوم دالة
return_hello
بارجاع مؤشر كقيمة
i32
. نحصل على هذه القيمة عن طريق الاتصال بـ
ToI32
. ثم نحصل على البيانات من الذاكرة باستخدام
instance.Memory.Data()
.
هذه الدالة تقوم بإرجاع شريحة الذاكرة لمثيل WebAssembly. يمكنك استخدامه مثل أي شريحة Go.
لحسن الحظ ، نحن نعرف طول السطر الذي نريد قراءته ، وبالتالي ، لقراءة المعلومات الضرورية ، يكفي استخدام
memory[pointer : pointer+13]
. ثم يتم تحويل بيانات القراءة إلى سلسلة.
إليك مثال يوضح آليات ذاكرة أكثر تقدماً عند استخدام رمز GoA WebAssembly.
المعايير
يحتوي مشروع go-ext-wasm ، كما رأينا للتو ، على واجهة برمجة تطبيقات ملائمة. الآن حان الوقت للحديث عن أدائها.
على عكس PHP أو Ruby ، فإن عالم Go لديه بالفعل حلول للعمل مع رمز wasm. على وجه الخصوص ، نحن نتحدث عن المشاريع التالية:
- الحياة من شبكة بيرلين - مترجم WebAssembly.
- Go Interpreter's Wagon هو مترجم وأدوات مجموعة WebAssembly.
استخدمت
المادة الموجودة في مشروع php-ext-wasm خوارزمية
الجسم n لدراسة الأداء. هناك العديد من الخوارزميات الأخرى المناسبة لفحص أداء بيئات تنفيذ التعليمات البرمجية. على سبيل المثال ، هذه هي خوارزمية
فيبوناتشي (النسخة العودية)
وخوارزمية بولارد used المستخدمة في الحياة. هذه هي خوارزمية ضغط Snappy. هذا الأخير يعمل بنجاح مع go-ext-wasm ، ولكن ليس مع Life أو Wagon. نتيجة لذلك ، تمت إزالته من مجموعة الاختبار. رمز الاختبار يمكن العثور عليها
هنا .
خلال الاختبارات ، تم استخدام أحدث إصدارات المشاريع البحثية. وهي الحياة 20190521143330-57f3819c2df0 و Wagon 0.4.0.
تعكس الأرقام الموضحة على الرسم البياني متوسط القيم التي تم الحصول عليها بعد 10 بدء من الاختبار. استخدمت الدراسة جهاز MacBook Pro 15 "2016 مع معالج Intel Core i7 2.9 جيجاهرتز و 16 جيجابايت من الذاكرة.
يتم تجميع نتائج الاختبار على طول المحور X وفقًا لأنواع الاختبارات. يُظهر المحور Y الوقت بالميلي ثانية اللازم لإكمال الاختبار. أصغر المؤشر ، كان ذلك أفضل.
مقارنة أداء Wasmer و Wagon و Life باستخدام تطبيقات الخوارزميات المختلفةمنصات الحياة والعربة ، في المتوسط ، تعطي تقريبا نفس النتائج. Wasmer ، في المتوسط ، هو 72 مرة أسرع.
من المهم ملاحظة أن Wasmer يدعم ثلاث
واجهات خلفية :
Singlepass و
Cranelift و
LLVM . الخلفية الافتراضية في مكتبة Go هي Cranelift (
هنا يمكنك معرفة المزيد عنها). سيؤدي استخدام LLVM إلى توفير أداء قريب من المستوى الأصلي ، ولكن تقرر البدء بـ Cranelift ، حيث أن هذه الواجهة الخلفية تعطي أفضل نسبة بين وقت التحويل البرمجي ووقت تنفيذ البرنامج.
هنا يمكنك أن تقرأ عن الخلفية المختلفة ، إيجابياتها وسلبياتها ، وفي أي المواقف ، من الأفضل استخدامها.
النتائج
مشروع مفتوح المصدر
go-ext-wasm هو مكتبة Go جديدة مصممة لتنفيذ شفرة wasm الثنائية. ويشمل
وقت التشغيل الغسالة . يتضمن الإصدار الأول منها واجهات برمجة التطبيقات (APIs) ، التي تنشأ الحاجة إليها في أغلب الأحيان.
أظهرت اختبارات الأداء أن Wasmer ، في المتوسط ، أسرع بـ 72 مرة من Life and Wagon.
أعزائي القراء! هل تخطط لاستخدام القدرة على تشغيل رمز wasm في Go باستخدام go-ext-wasm؟
