قوائم المهام لـ Rust: نظرة عامة، أمثلة وتوصيات
Rust — لغة برمجة أنظمة، تُستخدم بشكل متزايد لإنشاء خدمات ويب عالية التحميل، وخدمات مصغرة وأدوات معالجة بيانات. أحد العناصر الأساسية لهذه الأنظمة هو قائمة المهام (task queue)، التي تسمح بتوزيع العمل بكفاءة بين الخيوط أو المهام غير المتزامنة. في هذه المقالة، سنستعرض المكتبات الشائعة للعمل مع قوائم المهام في Rust، وميزاتها، وأدائها، وأمثلة الكود.
لماذا نحتاج إلى قوائم المهام؟
تحل قوائم المهام عدة مشاكل:
- موازنة التحميل — يتم توزيع المهام بين العمال.
- المعالجة غير المتزامنة — العمليات الطويلة لا تمنع الخيط الرئيسي.
- تحمل الأخطاء — عند تعطل عامل، يمكن إعادة تنفيذ المهمة.
- قابلية التوسع — سهولة إضافة عمال جدد.
المكتبات الرئيسية لقوائم المهام في Rust
1. tokio مع قنوات mpsc و broadcast
tokio — هو بيئة تشغيل غير متزامنة، المعيار الفعلي لـ Rust. لقوائم المهام، تُستخدم قنوات متعددة المنتجين، أحادية المستهلك (mpsc) أو قنوات البث (broadcast).
مثال:
use tokio::sync::mpsc;
#[tokio::main]async fn main() { let (tx, mut rx) = mpsc::channel(100);
// المنتج tokio::spawn(async move { for i in 0..10 { tx.send(i).await.unwrap(); } });
// المستهلك while let Some(msg) = rx.recv().await { println!("تم الاستلام: {}", msg); }}الإيجابيات: أداء عالٍ، تكامل مع نظام Tokio البيئي، دعم الضغط العكسي (backpressure).
السلبيات: يتطلب سياقًا غير متزامن، غير مناسب للمهام المتزامنة.
2. async-std مع القنوات
مشابه لـ tokio، ولكن بواجهة برمجة تطبيقات مختلفة. يستخدم async-channel أو flume داخليًا.
مثال:
use async_std::task;use async_channel::unbounded;
fn main() { task::block_on(async { let (s, r) = unbounded(); s.send(42).await.unwrap(); let val = r.recv().await.unwrap(); println!("القيمة: {}", val); });}الإيجابيات: واجهة برمجة تطبيقات بسيطة، دعم العمليات غير المتزامنة والمتزامنة.
السلبيات: أقل شهرة من Tokio.
3. flume — قنوات سريعة بدون تبعيات
flume — مكتبة توفر قنوات متعددة المنتجين، متعددة المستهلكين (MPMC). لا تتطلب بيئة تشغيل غير متزامنة ويمكن استخدامها في الكود المتزامن وغير المتزامن.
مثال:
use flume;
fn main() { let (tx, rx) = flume::unbounded();
std::thread::spawn(move || { tx.send("مرحبًا من الخيط").unwrap(); });
let msg = rx.recv().unwrap(); println!("{}", msg);}الإيجابيات: سريعة جدًا (مماثلة لـ crossbeam)، بسيطة، تدعم async.
السلبيات: لا يوجد دعم مدمج للضغط العكسي (موجود للقنوات المحدودة).
4. crossbeam — بدائيات منخفضة المستوى
crossbeam — مجموعة أدوات للبرمجة المتوازية. تحتوي على قنوات (crossbeam-channel)، والتي تعد من الأسرع في Rust.
مثال:
use crossbeam_channel::unbounded;
fn main() { let (s, r) = unbounded(); s.send("Hello").unwrap(); let msg = r.recv().unwrap(); println!("{}", msg);}الإيجابيات: أقصى أداء