العوازل في لغة دارت، يتم تشغيل جميع التعليمات البرمجية في سياق عزل يسمى Isolate. هذه العوازل توفر بيئة مستقلة لتشغيل الأكواد بدون مشاركة الحالة مع العوازل الأخرى. على عكس لغات البرمجة الأخرى التي تعتمد على “الخيوط” (threads) التي تشارك الذاكرة، توفر Dart عوازل تتيح عملية التنفيذ المتوازي بدون تعارضات في الذاكرة. يتم التواصل بين العوازل عن طريق الرسائل، مما يضمن أن كل عزل لديه ذاكرته الخاصة ولا يشارك البيانات مباشرة مع العوازل الأخرى.
ما هي العوازل في لغة Dart؟
في لغة Dart، كل تطبيق يتم تشغيله داخل عزل رئيسي يسمى main isolate. إذا كنت بحاجة إلى تنفيذ عمليات مكثفة دون تعطيل واجهة المستخدم، يمكنك إنشاء Isolate جديد لتنفيذ هذه العمليات في بيئة معزولة. على سبيل المثال، عند التعامل مع عمليات حسابية كبيرة أو عمليات إدخال/إخراج كثيفة، يمكن استخدام العوازل لتجنب تجميد التطبيق.
“اقرأ أيضاً: شرح استخدام ويدجت FittedBox في فلاتر“
كيفية إنشاء واستخدام العوازل في لغة دارت؟
لإنشاء Isolate جديد في Dart، نستخدم الدالة Isolate.spawn
التي تنشئ وتبدأ تشغيل Isolate جديد. يتم تمرير دالة تنفيذ ورسالة أولية إلى العازل الجديد.
مثال بسيط لإنشاء Isolate جديد:
import 'dart:isolate'; // دالة لتنفيذ العمليات داخل العزل void heavyComputation(SendPort sendPort) { int result = 0; for (int i = 0; i < 1000000000; i++) { result += i; } sendPort.send(result); // إرسال النتيجة إلى العازل الرئيسي } void main() async { ReceivePort receivePort = ReceivePort(); // إنشاء منفذ لتلقي الرسائل // تشغيل عازل جديد await Isolate.spawn(heavyComputation, receivePort.sendPort); // انتظار الرسالة من العازل receivePort.listen((data) { print("Result from Isolate: $data"); receivePort.close(); // إغلاق المنفذ بعد الانتهاء }); }
الناتج:
Result from Isolate: 499999999500000000
في هذا المثال، تم إنشاء Isolate جديد لتنفيذ عملية حسابية ثقيلة جدا (إجمالي الأرقام من 0 إلى 1 مليار) . يتم إرسال النتيجة من العازل الجديد إلى العازل الرئيسي عبر SendPort
وReceivePort
.
“اقرأ أيضاً: شرح استخدام ويدجت SwitchListTile في فلاتر“
مثال يوضح أهمية استخدام العوازل في لغة دارت
لنقم بكتابة مثال يوضح تأثير استخدام العوازل في لغة دارت مقابل عدم استخدامها عند تنفيذ عملية حسابية ثقيلة. سنرى كيف يؤدي استخدام العوازل إلى تحسين استجابة التطبيق وعدم تجميد واجهة المستخدم.
مثال بدون استخدام العوازل في لغة دارت (Isolates)
import 'dart:async'; void heavyComputation() { int result = 0; for (int i = 0; i < 1000000000; i++) { result += i; } print("Result: $result"); } void main() { print("Starting heavy computation..."); // تنفيذ الحساب مباشرةً في العازل الرئيسي heavyComputation(); // هذا السطر سيتم تنفيذه بعد انتهاء العملية الحسابية print("Finished heavy computation"); }
الشرح:
- في هذا المثال، يتم تنفيذ عملية حسابية ثقيلة في العازل الرئيسي (
main isolate
)، وهذا يعني أن كل المهام الأخرى بما فيها طباعة “Finished heavy computation” ستنتظر حتى تنتهي عملية الحساب. - إذا كان هناك واجهة مستخدم في التطبيق، فإنها ستتوقف عن الاستجابة حتى تنتهي العملية.
الناتج بدون استخدام العوازل:
Starting heavy computation... Result: 499999999500000000 Finished heavy computation
كما نلاحظ، لا يتم طباعة “Finished heavy computation” إلا بعد انتهاء العملية الحسابية، مما يعني أن واجهة المستخدم ستكون مجمدة خلال هذه الفترة.
“اقرأ أيضاً: شرح تبديل الحالة في دارت (Switch Case In Dart)“
مثال باستخدام العوازل في لغة دارت (Isolates)
import 'dart:isolate'; // دالة تنفيذ داخل العازل void heavyComputation(SendPort sendPort) { int result = 0; for (int i = 0; i < 1000000000; i++) { result += i; } sendPort.send(result); // إرسال النتيجة إلى العازل الرئيسي } void main() async { print("Starting heavy computation..."); ReceivePort receivePort = ReceivePort(); // إنشاء منفذ لتلقي الرسائل // تشغيل العازل الجديد await Isolate.spawn(heavyComputation, receivePort.sendPort); // انتظار الرسالة من العازل receivePort.listen((data) { print("Result from Isolate: $data"); print("Finished heavy computation"); receivePort.close(); // إغلاق المنفذ بعد استلام الرسالة }); // يمكن طباعة الرسائل أو تنفيذ العمليات الأخرى هنا بدون تجميد print("Main isolate continues working..."); }
الشرح:
- في هذا المثال، يتم نقل عملية الحساب الثقيلة إلى عازل مستقل باستخدام
Isolate.spawn
. - يتم إرسال النتيجة النهائية للعازل الرئيسي عبر الرسائل باستخدام
SendPort
وReceivePort
. - العازل الرئيسي يواصل العمل ويستطيع طباعة “Main isolate continues working…” دون الانتظار حتى تنتهي العملية الحسابية.
الناتج باستخدام العوازل:
Starting heavy computation... Main isolate continues working... Result from Isolate: 499999999500000000 Finished heavy computation
كما نلاحظ، يتم طباعة “Main isolate continues working…” فوراً، مما يدل على أن العازل الرئيسي لا يتوقف عن العمل أثناء تنفيذ العملية الحسابية في العازل المستقل.
الفرق بين الحالتين:
- بدون العوازل: التطبيق يتوقف عن العمل مؤقتًا حتى تنتهي العملية الحسابية، مما يسبب تجميد واجهة المستخدم.
- باستخدام العوازل: التطبيق يستمر في العمل بشكل طبيعي، حتى مع تنفيذ العملية الحسابية الثقيلة في الخلفية، مما يحافظ على استجابة واجهة المستخدم.
هذا المثال يوضح أهمية العوازل في تحسين أداء التطبيقات التي تحتاج إلى تنفيذ مهام ثقيلة دون التأثير على تجربة المستخدم.
“اقرأ أيضاً: شرح استخدام ويدجت AnimatedList في فلاتر“
الفرق بين Isolates و Multithreading
في اللغات الأخرى مثل Java أو Python، يتم استخدام “الخيوط” (Threads) لتنفيذ العمليات المتعددة في نفس الوقت. ومع ذلك، هذه الخيوط تشارك نفس الذاكرة، مما يؤدي إلى احتمالية حدوث مشاكل تنافسية (race conditions) أو تعارضات في الوصول إلى الذاكرة. في Dart، تم تصميم العوازل لتجنب هذه المشاكل عن طريق فصل كل Isolate في ذاكرته الخاصة.
“اقرأ أيضاً: شرح استخدام ويدجت ShaderMask في فلاتر“
استخدام العوازل بالتوازي في التطبيقات
أحد أهم استخدامات العوازل في لغة دارت هو تحسين الأداء في التطبيقات التي تتطلب عمليات حسابية ثقيلة أو عمليات إدخال/إخراج (I/O) مكثفة. من خلال نقل هذه العمليات إلى عوازل منفصلة، يمكنك التأكد من أن واجهة المستخدم الرئيسية ستظل سلسة ولا تتأثر بتلك العمليات.
مثال آخر: تحميل البيانات بشكل متوازي
import 'dart:isolate'; // دالة لتحميل البيانات داخل عازل جديد void fetchData(SendPort sendPort) { // محاكاة تحميل البيانات String data = "Data from isolate"; sendPort.send(data); } void main() async { ReceivePort receivePort = ReceivePort(); // تشغيل العازل الجديد await Isolate.spawn(fetchData, receivePort.sendPort); // انتظار البيانات receivePort.listen((data) { print("Received: $data"); receivePort.close(); }); }
الناتج:
Received: Data from isolate
مزايا استخدام العوازل في لغة دارت:
- عدم المشاركة في الذاكرة: كل Isolate لديه ذاكرته الخاصة، مما يعني عدم وجود مشاكل التزامن أو التعارضات في الذاكرة.
- التواصل عبر الرسائل: يتم التواصل بين العوازل عبر الرسائل فقط، مما يسهل إدارتها.
- الأمان: يعزز العازل الأمان نظرًا لعدم وجود مشاركة مباشرة للبيانات بين العوازل.
“اقرأ أيضاً: شرح استخدام ويدجت CircleAvatar في فلاتر“
متى يجب استخدام العوازل في لغة دارت؟
يمكن استخدام العوازل في لغة دارت في السيناريوهات التالية:
- عمليات الحوسبة المكثفة: مثل معالجة الصور أو الحسابات العلمية.
- عمليات الإدخال/الإخراج الطويلة: مثل تحميل البيانات من الإنترنت أو قراءة الملفات الكبيرة.
- تحسين الأداء في التطبيقات الكبيرة: تجنب تجميد واجهة المستخدم عن طريق توزيع العمل على عوازل مختلفة.
“اقرأ أيضاً: شرح الـ Asynchronous في لغة دارت (Dart)“
توفر العوازل في لغة دارت طريقة قوية لتنفيذ العمليات بشكل متوازي بدون القلق من مشاكل التزامن أو تعارضات الذاكرة. عن طريق فصل العمليات في عوازل مختلفة والتواصل عبر الرسائل، يمكن تحسين أداء التطبيقات بشكل كبير، خاصة تلك التي تحتوي على عمليات ثقيلة أو طويلة الأمد.