تحسين أداء تطبيقات C++: طرق عملية

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

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

ابدأ الدورة

مقدمة: لماذا يعتبر تحسين C++ فنًا



تُعتبر لغة C++ بحق واحدة من أكثر لغات البرمجة أداءً. ومع ذلك، فإن الأداء العالي لا يأتي تلقائيًا - بل يجب اكتسابه. غالبًا ما يكتب المطورون كودًا يعمل أبطأ بمقدار 2-10 مرات مما يمكن أن يكون عليه، وذلك ببساطة بسبب عدم معرفة المزالق النموذجية أو الاستخدام غير الصحيح للمكتبة القياسية.



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



المقالة موجهة للمطورين الذين هم على دراية بأساسيات C++، ولكنهم يرغبون في رفع أداء برامجهم إلى مستوى جديد.



1. التنميط: لا تخمن - قس



القاعدة الأولى للتحسين: لا تقم أبدًا بالتحسين بشكل أعمى. بدون التنميط، تخاطر بإضاعة ساعات في تسريع كود يعمل بالفعل بسرعة، بينما تظل نقطة الاختناق غير مكتشفة.



أدوات التنميط

  • Valgrind (Callgrind) - تحليل مفصل لوقت التنفيذ وأخطاء التخزين المؤقت.
  • perf (Linux) - أداة تنميط نظامية بأقل تكاليف إضافية.
  • Visual Studio Profiler - أداة مدمجة لنظام Windows.
  • Google Benchmark - للمعايير الدقيقة للدوال الفردية.


مثال لمعيار دقيق باستخدام Google Benchmark

#include <benchmark/benchmark.h>#include <vector>#include <algorithm>

// النسخة البطيئة: النسخ بالقيمةstatic void BM_SlowSort(benchmark::State& state) { std::vector<int> data(state.range(0)); std::generate(data.begin(), data.end(), std::rand); for (auto _ : state) { auto copy = data; // نسخ في كل مرة std::sort(copy.begin(), copy.end()); }}BENCHMARK(BM_SlowSort)->Range(8, 8<<10);

// النسخة السريعة: الفرز في المكانstatic void BM_FastSort(benchmark::State& state) { std::vector<int> data(state.range(0)); std::generate(data.begin(), data.end(), std::rand); for (auto _ : state) { auto copy = data; std::sort(copy.begin(), copy.end()); }}BENCHMARK(BM_FastSort)->Range(8, 8<<10);

BENCHMARK_MAIN();


سيظهر التنميط أن الفرق بين النسخ والعمل في المكان يمكن أن يصل إلى 50% أو أكثر. قم دائمًا بالقياس قبل تغيير الكود.



2. اختيار الحاويات والخوارزميات الفعالة



تقدم المكتبة القياسية لـ C++ العديد من الحاويات، لكن ليست جميعها مفيدة بنفس القدر لكل مهمة. يمكن أن يؤدي الاختيار الخاطئ إلى تخصيصات غير ضرورية، وأخطاء في التخزين المؤقت، وفقدان الأداء.



متى تستخدم std::vector ومتى تستخدم std::list؟

  • std::vector - دائمًا تقريبًا الخيار الأفضل للبيانات المتسلسلة. يوفر توطينًا في الذاكرة (صديق للتخزين المؤقت) وتكاليف إضافية ضئيلة.
  • std::list - مبرر فقط إذا كنت بحاجة إلى إدراج/حذف عناصر متكرر في منتصف الحاوية، وكان عدد العناصر كبيرًا جدًا.
  • std::deque - جيد لقوائم الانتظار حيث يتم الإدراج/الحذف من كلا الطرفين.


مثال: مقارنة الأداء

#include <vector>#include <list>#include <chrono>#include <iostream>

int main() { const int N = 100000; // الإدراج في بداية vector (بطيء) auto start = std::chrono::high_resolution_clock::now(); std::vector<int> v; for (int i = 0; i < N; ++i) { v.insert(v.begin(), i); } auto end = std::chrono::high_resolution_clock:

المدونات

توصيات الكتب