async fn تُعيد Future
دالة async لا تنفّذ جسمها فورًا، بل تُعيد قيمة تنفّذ السمة Future — ولا شيء
يحدث حتى تُشغَّل هذه القيمة لاحقًا:
async fn fetch_greeting() -> String {
// تخيّل هنا طلب شبكة حقيقي
String::from("مرحبًا")
}
استدعاء fetch_greeting() وحده لا يفعل شيئًا — فقط يبني Future كسولًا.
await لتشغيل المهمة
.await هو ما يشغّل الـ Future فعليًا ويستخرج نتيجته، داخل دالة async
أخرى:
async fn greet() {
let msg = fetch_greeting().await; // ينفّذ وينتظر النتيجة هنا
println!("{msg}");
}
لماذا لا تعمل async بمفردها؟
خلافًا للغات أخرى، Rust لا تشحن وقت تشغيل (runtime) مدمجًا لتنفيذ
الـ Futures — عليك اختيار حزمة خارجية توفّره، وأشهرها Tokio:
#[tokio::main]
async fn main() {
greet().await;
}
#[tokio::main] يحوّل main العادية إلى نقطة دخول تُشغَّل داخل وقت تشغيل
Tokio.
async مقابل الخيوط (Threads)
| الجانب | خيوط نظام التشغيل (Threads) | async/await |
|---|---|---|
| التكلفة | كل خيط يستهلك ذاكرة ومعالجة حتى لو كان خاملًا | آلاف المهام على عدد قليل من الخيوط |
| الأنسب لـ | مهام تستهلك المعالج بكثافة (CPU-bound) | انتظار شبكة/ملفات (IO-bound) |
| التنفيذ | متوازٍ فعليًا عبر أنوية المعالج | تعاوني (cooperative) عبر polling |
💡 استخدم async للخوادم وطلبات الشبكة وقواعد البيانات (IO-bound)، واستخدم الخيوط العادية (الدرس السابق: التزامن) للحوسبة الثقيلة (CPU-bound). كثيرًا ما يُجمَع بينهما في نفس المشروع.
🎯 التالي: خلاصة المسار.