Rust: أسرار الأداء الأقصى — التنميط والتحسين

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

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

ابدأ الدورة

لماذا Rust سريع، ولكن ليس دائمًا؟

\n

Rust هي لغة تعد بأداء C++ مع أمان الذاكرة. ولكن حتى في Rust يمكنك كتابة كود بطيء. قراران خاطئان — وستبدأ خدمتك في التباطؤ تحت الحمل. الخبر الجيد: Rust يمنحك جميع الأدوات لتحديد وإزالة نقاط الاختناق. في هذه المقالة، سنشرح كيفية تنميط كود Rust وأي تقنيات التحسين تعمل حقًا.

\n\n

لن نتحدث بشكل نظري. سترى أمثلة حقيقية للكود، وستتعلم كيفية استخدام perf وflamegraph وvalgrind والمقاييس المدمجة. بعد القراءة، ستتمكن من إجراء تدقيق أداء لمشروعك بنفسك.

\n\n

مجموعة أدوات تنميط Rust

\n

قبل تحسين أي شيء، تحتاج إلى فهم ما الذي يبطئ الأمور. إليك ثلاث أدوات عملية ستساعدك على النظر داخل البرنامج.

\n\n

1. المقاييس باستخدام cargo bench

\n

الطريقة القياسية لقياس الأداء هي كتابة معيار أداء. في Rust، يتم استخدام crate criterion أو إطار الاختبار المدمج. مثال:

\n\n
use criterion::{black_box, criterion_group, criterion_main, Criterion};\n\nfn fibonacci(n: u64) -> u64 {\n    match n {\n        0 => 0,\n        1 => 1,\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(black_box(20))));\n}\n\ncriterion_group!(benches, bench_fib);\ncriterion_main!(benches);\n
\n\n

التشغيل: cargo bench. ستحصل على وقت التنفيذ والانحراف والمقارنة مع عمليات التشغيل السابقة. هذه هي القاعدة التي يجب أن تبدأ بها أي تحسين.

\n\n

2. التنميط باستخدام perf وflamegraph

\n

عندما تحتاج إلى معرفة أي الوظائف تستهلك المعالج، استخدم perf. اجمع البيانات، ثم قم بتصورها على شكل مخطط لهب:

\n\n
# جمع البيانات\nperf record -g ./target/release/my_app\n# إنشاء flamegraph\nperf script | stackcollapse-perf.pl | flamegraph.pl > profile.svg\n
\n\n

سيظهر لك مخطط اللهب الأجزاء "الساخنة" من الكود. كلما كانت الكتلة أوسع، زاد الوقت المستغرق في هذه الوظيفة. هذه هي الطريقة الأكثر وضوحًا للعثور على نقطة الاختناق.

\n\n

3. البحث عن تسرب الذاكرة باستخدام Valgrind

\n

Rust يحمي من تسرب الذاكرة على مستوى الترجمة، ولكن ليس من جميعها. على سبيل المثال، إذا كنت تستخدم Rc أو Arc مع مراجع دائرية، فقد لا يتم تحرير الذاكرة. سيساعدك Valgrind في اكتشاف ذلك:

\n\n
valgrind --tool=massif ./target/debug/my_app\n
\n\n

سيظهر Massif مقدار الذاكرة التي يستهلكها البرنامج في كل لحظة. إذا لم ينخفض الرسم البياني بعد انتهاء العمل — فابحث عن تسرب.

\n\n

تقنيات عملية لتحسين كود Rust

\n

الآن بعد أن عرفت ما تبحث عنه، دعنا نشرح كيفية إصلاحه. إليك خمس طرق مثبتة تعمل حقًا على تسريع الكود.

\n\n

1. التجريدات ذات التكلفة الصفرية: استخدم التكرارات بشكل صحيح

\n

يتم ترجمة التكرارات في Rust إلى كود بنفس كفاءة الحلقات اليدوية. ولكن فقط إذا لم تقم بعمل نسخ غير ضرورية. قارن:

\n\n
// سيء: إنشاء Vec، نسخ، تصفية\nlet result: Vec<u32> = data.iter().filter(|x| x % 2 == 0).collect();\n// جيد: العمل مع المكرر بدون مجموعات وسيطة\nlet sum: u32 = data.iter().filter(|x| x % 2 == 0).sum();\n
\n\n

الخيار الثاني لا يخصص ذاكرة لمتجه مؤقت. إذا كنت تحتاج فقط إلى قيمة واحدة — لا تجمع.

\n\n

2. التخزين المؤقت للنتائج

\n

إذا تم استدعاء دالة بشكل متكرر بنفس الوسائط، قم بتخزين النتيجة مؤقتًا. استخدم HashMap أو crate lru للحد من حجم ذاكرة التخزين المؤقت:

\n\n
use std::collections::HashMap;\n\nfn expensive_calc(x: u64) -> u64 {\n    // ... حسابات طويلة\n    x * x\n}\n\nfn c                

المدونات

توصيات الكتب