محتويات الدورة

C++ / المتقدم / الدرس 18

قياس الأداء وتصميم الواجهات

حسّن برنامجًا صحيحًا بقياسات ممثلة، ثم صمّم واجهات تظهر الملكية والأخطاء والتعقيد والتوافق بصدق.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • فصل التعقيد الخوارزمي والتخصيص ومحلية البيانات وأدلة التوقيت.
  • تحليل عدد صحيح محصور دون ملكية خفية أو قبول جزئي.
  • مراجعة عقد العمر والخطأ والأداء في الواجهة.

قياس عبء عمل ممثل

الأداء خاصية لعبء عمل على بناء وآلة محددين. ابدأ بسلوك مرجعي صحيح وهدف قابل للقياس مثل خفض زمن المعالجة الوسيط لتوزيع مدخلات معلوم. استخدم التنميط لمعرفة العمل المكلف قبل تغيير الواجهات. يصف Big-O النمو، وتؤثر التخصيصات ومحلية المخبأ والتفرعات ونداءات النظام في الثوابت. قد يحذف المحسّن قياسًا مصغرًا لا تُستخدم نتيجته، وقد يشوه بناء التصحيح المقارنة. سجّل الأعلام والحجم والتكرار والبيئة واذكر التباين بدل اختراع سرعة عالمية.

تقليل العمل غير الضروري مع حفظ المعنى

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

cpp فحص صحة قبل توقيت تغييرات التخصيص
#include <iostream>
#include <vector>
int main() {
    std::vector<int> squares;
    squares.reserve(4);
    for (int value{1}; value <= 4; ++value) { squares.push_back(value * value); }
    int total{};
    for (int value : squares) { total += value; }
    std::cout << squares.size() << " " << total << "\n";
}
الناتج المتوقع
4 30

المربعات أربعة: واحد وأربعة وتسعة وستة عشر ومجموعها ثلاثون. لا يُدّعى زمن يعتمد على الآلة أو سعة دقيقة.

إظهار القبول والفشل

يستعير مثال التحليل الإدخال عبر string_view طوال الاستدعاء ويعيد optional<int> بالقيمة. تحلل from_chars العدد دون تنسيق تدفق يعتمد على الإعدادات المحلية أو سلسلة مملوكة منفصلة. تتضمن نتيجتها رمز خطأ ومؤشر أول محرف غير مستهلك. افحصهما لرفض تجاوز المجال والنص المتبقي، ثم افحص مجال التطبيق منفصلًا. ترفض الدالة العرض الفارغ قبل حساب المؤشرات ولا تحتفظ به. تتوافر from_chars الصحيحة منذ C++17؛ ولا يفترض هذا المقرر أغلفة نتائج أحدث أو دعم تحليل عشري معين.

cpp عقد تحليل محصور يشمل الإدخال كله
#include <charconv>
#include <iostream>
#include <optional>
#include <string_view>
#include <system_error>
std::optional<int> parse_count(std::string_view text) {
    if (text.empty()) { return std::nullopt; }
    int value{};
    const auto result = std::from_chars(text.data(), text.data() + text.size(), value);
    if (result.ec != std::errc{} || result.ptr != text.data() + text.size() ||
        value < 0 || value > 1000) { return std::nullopt; }
    return value;
}
int main() {
    const auto valid = parse_count("42");
    const auto invalid = parse_count("42x");
    std::cout << valid.value() << " " << std::boolalpha << invalid.has_value() << "\n";
}
الناتج المتوقع
42 false

تُقبل 42. أما 42x فلها بادئة رقمية صالحة ونص متبقٍ، فتُرفض كمدخل كامل.

الواجهة السريعة تحتاج إلى عقد عمر

قد تتجنب الاستعارة عبر string_view أو span النسخ لكنها تضيف اعتمادًا على عمر المصدر. إعادة عرض إلى مخزن محلي غير صالحة مهما كانت القياسات. قد يكون أخذ قيمة أفضل إذا وجب الاحتفاظ بالبيانات. وثّق ملكية النتائج والمدخلات التي قد تبطل وتخزين ردود النداء والتعقيد المعتمد عليه. تجنب كشف تخزين متجه داخلي لتوفير نسخة صغيرة إذا منع التطوير أو أنشأ مستعيرين هشين. يوازن التصميم الكلفة بعقد يظل قابلًا للمراجعة.

دمج خدمة تقارير صغيرة

في مشروع ختامي اقرأ أعداد عناصر اصطناعية وافحص كل إدخال كاملًا وخزّن سجلات مملوكة في vector واحسب تقريرًا بخوارزميات قياسية واعرض دالة تقرير خالصة. أبقِ التعامل مع الطرفي عند الحدود. اختر الاستثناءات لفشل الإنشاء الاستثنائي والنتائج الصريحة للسجلات غير الصالحة المتوقعة. اختبر الفراغ والنص المشوه والحدود والتكرار والترتيب الحتمي. قِس بعد نجاح الاختبارات نفسها للتحسين المقترح. عند إضافة التزامن حدّد الملكية والمزامنة قبل الموازاة؛ فقد تزيد الخيوط الكلفة للأعمال الصغيرة. انشر الافتراضات المقاسة بدل وعد إنتاجية غير مثبتة.

الأخطاء الشائعة وإصلاحها

قياس أسرع ينتج نتائج مختلفة.

لماذا يحدث؟
غيّر التحسين العقد الملحوظ.
كيف تصلحه؟
استعد الصحة وقارن أحمالًا متكافئة.
كيف تتجنب تكراره؟
اشترط اختبارات منع العودة قبل قبول تحسن التوقيت.

محلل يقبل 42x عددًا كاملًا.

لماذا يحدث؟
فُحص رمز خطأ التحويل فقط.
كيف تصلحه؟
اشترط مساواة المؤشر المعاد نهاية الإدخال.
كيف تتجنب تكراره؟
اختبر بادئات صالحة تتبعها محارف غير مرغوبة.

string_view معاد يصبح متدليًا.

لماذا يحدث؟
كانت السلسلة الخلفية محلية أو أعيد تخصيصها لاحقًا.
كيف تصلحه؟
أعد سلسلة مملوكة أو وثّق مصدرًا ثابتًا يملكه المستدعي.
كيف تتجنب تكراره؟
أدرج الملكية في مراجعة الواجهات الموجهة للأداء.

اختبر فهمك

1. صنّف مدخلات parse_count: "0" و"1000" و"1001" و" 42" و"42x"، وحدّد قاعدة رفض كل مدخل غير صالح.

اعرض الحل المشروح

يُقبل صفر وألف. يفشل ألف وواحد في مجال التطبيق. لا تتجاوز from_chars الصحيحة المسافة الأولية فيفشل التحويل. وتترك 42x لاحقة غير مستهلكة فتفشل في فحص الإدخال الكامل. السياسة صارمة عمدًا؛ وإذا سُمحت المسافات فاحذفها صراحة ووثّق التحويل منفصلًا.

2. أظهر قياس أن إدخال span أسرع من نسخ vector، لكن الواجهة تضع العمل في طابور بعد العودة. اقترح تصميم ملكية.

اعرض الحل المشروح

يحتاج العمل المنتظر إلى بيانات مملوكة أو مالك صريح يغطي عمره التنفيذ. اقبل vector بالقيمة وانقله إلى المهمة أو احتفظ بمالك مشترك ثابت مبرر. لا يوفّر span العمر وحده. قِس عبء الطابور كاملًا بما يشمل انتقال الملكية بدل تحسين استدعاء متزامن لا يطابق الاستخدام الفعلي.

أهم ما تعلمته

  • قِس سلوكًا متكافئًا بشروط معلومة.
  • أظهر سياسات التحليل والملكية والخطأ.
  • تقيد الصحة وعقود العمر كل تحسين.

المراجع الرسمية