مقدمة: لماذا Rust سريع بالفعل، لكنه ليس الحد الأقصى
\n\nتُعتبر Rust بحق واحدة من أكثر لغات البرمجة النظامية أداءً. بفضل التجريدات ذات التكلفة الصفرية (zero-cost abstractions) ونظام الملكية الصارم، يعمل الكود المكتوب بلغة Rust غالبًا بنفس سرعة الكود المكافئ بلغة C أو C++. ومع ذلك، حتى في Rust توجد "مزالق" قد تبطئ التطبيق، خاصة لدى المطورين المبتدئين.
\n\nفي هذه المقالة، سنستعرض المبادئ الأساسية والتقنيات العملية لتحسين أداء تطبيقات Rust. ستتعلم كيفية تنميط الكود، وتجنب التخصيصات غير الضرورية، والعمل بكفاءة مع المجموعات، واستخدام قوة المترجم. المادة موجهة للمبتدئين، لذا ستكون جميع الأمثلة بسيطة ومفهومة قدر الإمكان.
\n\nهل أنت مستعد لجعل كود Rust الخاص بك أسرع؟ هيا بنا!
\n\n1. التنميط: قم بالقياس أولاً، ثم قم بالتحسين
\n\nقبل تحسين أي شيء، تحتاج إلى فهم ما الذي يسبب البطء. في Rust، توجد أدوات ممتازة لذلك.
\n\n1.1. المعايير مع cargo bench
\n\nالطريقة القياسية هي استخدام المعايير (benchmarks). تتيح لك قياس وقت تنفيذ دوال محددة.
\n\n// في الملف benches/my_bench.rs\nuse criterion::{criterion_group, criterion_main, Criterion};\n\nfn fibonacci(n: u64) -> u64 {\n match n {\n 0 => 1,\n 1 => 1,\n n => fibonacci(n-1) + fibonacci(n-2),\n }\n}\n\nfn bench_fib(c: &mut Criterion) {\n c.bench_function("fib 20", |b| b.iter(|| fibonacci(20)));\n}\n\ncriterion_group!(benches, bench_fib);\ncriterion_main!(benches);\n\n\nللتشغيل، أضف إلى Cargo.toml:
[dev-dependencies]\ncriterion = "0.5"\n\n[[bench]]\nname = "my_bench"\nharness = false\n\nثم نفذ cargo bench. ستحصل على أرقام دقيقة: وقت التنفيذ، الانحراف المعياري، والمقارنة مع التشغيلات السابقة.
1.2. تنميط وحدة المعالجة المركزية (CPU) والذاكرة
\n\nللتحليل الأعمق، استخدم:
\n- \n
- perf (لينكس) — أداة تنميط على مستوى النواة. \n
- Valgrind — للبحث عن تسربات الذاكرة وتحليل ذاكرة التخزين المؤقت (cache). \n
- flamegraph — تصور "النقاط الساخنة" في الكود. \n
مثال على توليد flamegraph:
\ncargo install flamegraph\ncargo flamegraph --bin my_app\n# افتح flamegraph.svg في المتصفح\n\n\nسيظهر لك flamegraph أي الدوال تستهلك أكبر قدر من الوقت. سيساعدك هذا على التركيز على الأمور الرئيسية.
\n\n2. التعامل مع الذاكرة: تجنب التخصيصات غير الضرورية
\n\nالتخصيصات في الكومة (heap) هي أحد أكثر أسباب بطء الكود شيوعًا. تمنحك Rust تحكمًا كاملاً في الذاكرة، لكن المبتدئين غالبًا ما يفرطون في استخدام Box و Vec و String.
2.1. استخدم المكدس (stack) بدلاً من الكومة (heap)
\n\nكلما أمكن، قم بتخزين البيانات على المكدس. على سبيل المثال، بدلاً من Vec لمجموعة صغيرة ثابتة، استخدم مصفوفة:
// بطيء: تخصيص في الكومة\nlet data: Vec<i32> = vec![1, 2, 3, 4, 5];\n\n// سريع: المكدس\nlet data: [i32; 5] = [1, 2, 3, 4, 5];\n\n\n2.2. التخصيص المسبق للذاكرة
\n\nإذا كان حجم المجموعة معروفًا مسبقًا، استخدم with_capacity:
// سيء: الكثير من عمليات إعادة التخصيص\nlet mut v = Vec::new();\nfor i in 0..1000 {\n v.push(i);\n}\n\n// جيد: تخصيص واحد\nlet mut v = Vec::with_capacity(1000);\nfor i in 0..1000 {\n v.push(i);\n}\n\n\n2.3. تجنب الاستنساخ (cloning)
\n\nاستنساخ السلاسل النصية والهياكل الكبيرة هي عملية مكلفة. استخدم الاقتراض (&str بدلاً من String):
fn process(s: &str) { /* ... */ }\n\n// سيء: استنساخ\nlet s = String::from("hello");\nprocess(&s.clone());\n\n// جيد: اقتراض\nprocess(&s);\n\n\n