البرمجة غير المتزامنة في Rust: دليل شامل مع أمثلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة في البرمجة غير المتزامنة في Rust



البرمجة غير المتزامنة هي نموذج يسمح بتنفيذ عمليات الإدخال والإخراج (طلبات الشبكة، قراءة الملفات، العمل مع قواعد البيانات) دون حظر سير التنفيذ الرئيسي. في Rust، يتم تنفيذ عدم التزامن من خلال نظام Future والكلمات المفتاحية async/await. على عكس تعدد الخيوط، يعمل الكود غير المتزامن في خيط واحد، ويتنقل بين المهام أثناء الانتظار.



في هذا الدليل، سنشرح:

  • أساسيات async/await في Rust
  • العمل مع crate tokio — بيئة التشغيل غير المتزامنة الأكثر شيوعًا
  • إنشاء ودمج Future
  • أمثلة عملية: عميل HTTP غير متزامن ومؤقتات


المقال موجه للمطورين الملمين ببناء جملة Rust الأساسية. إذا كنت مبتدئًا — نوصي أولاً بدراسة أساسيات اللغة على PythonLib.



أساسيات async/await و Future في Rust



ما هو Future؟



Future هو trait يمثل عملية غير متزامنة يمكن أن تكتمل في المستقبل. في Rust، Future كسول: لا يفعل شيئًا حتى يتم استطلاعه (poll). بيئة التشغيل غير المتزامنة (مثل Tokio) هي المسؤولة عن الاستطلاع.



مثال بسيط لدالة غير متزامنة:



use std::time::Duration;

async fn say_hello() { println!("مرحبًا من العالم غير المتزامن!"); tokio::time::sleep(Duration::from_secs(1)).await; println!("مرت ثانية واحدة");}

#[tokio::main]async fn main() { say_hello().await;}


الكلمة المفتاحية async تحول الدالة إلى Future. استدعاء .await يوقف تنفيذ المهمة الحالية حتى اكتمال Future، دون حظر الخيط.



دورة حياة المهمة غير المتزامنة



عند استدعاء .await، يحدث التالي:

  1. تقوم بيئة التشغيل باستطلاع Future (تستدعي طريقة poll())
  2. إذا كان Future جاهزًا — يتم إرجاع النتيجة
  3. إذا كان Future ينتظر (مثل عملية شبكة) — تتحول بيئة التشغيل إلى مهمة أخرى
  4. عندما يصبح المورد متاحًا، تستأنف بيئة التشغيل المهمة


خاصية مهمة في Rust: يمكن استدعاء .await فقط داخل دالة غير متزامنة أو كتلة async {}. محاولة استخدامه في سياق متزامن ستؤدي إلى خطأ في الترجمة.



العمل العملي مع Tokio



التثبيت والإعداد



Tokio هي بيئة تشغيل غير متزامنة لـ Rust، توفر جدولة المهام، المؤقتات، مآخذ الشبكة وغيرها الكثير. للبدء، أضف إلى Cargo.toml:



[dependencies]tokio = { version = "1", features = ["full"] }


العلامة features = ["full"] تفعّل جميع إمكانيات Tokio. للإنتاج، من الأفضل اختيار الميزات الضرورية فقط.



تشغيل مهام غير متزامنة متعددة



واحدة من المزايا الرئيسية لعدم التزامن هي التنفيذ المتوازي للعديد من المهام. استخدم tokio::spawn لتشغيل المهام في الخلفية:



use tokio::time::{sleep, Duration};

async fn task(name: &str, seconds: u64) { println!("المهمة {} بدأت", name); sleep(Duration::from_secs(seconds)).await; println!("المهمة {} اكتملت بعد {} ثانية", name, seconds);}

#[tokio::main]async fn main() { let handle1 = tokio::spawn(task("A", 2)); let handle2 = tokio::spawn(task("B", 1));

// ننتظر اكتمال كلتا المهمتين let _ = tokio::join!(handle1, handle2); println!("جميع المهام مكتملة");}


ماكرو tokio::join! ينتظر اكتمال جميع Future المُمررة. إذا اكتملت مهمة واحدة مبكرًا، لن يتوقف التنفيذ — سننتظر الباقي.



معالجة الأخطاء في الكود غير المتزامن

المدونات

توصيات الكتب