سؤال

أخطط للمشاركة في تطوير رمز مكتوب بلغة C لتحليل Monte Carlo للمشاكل المعقدة. تخصص هذه الرموز صفائف بيانات ضخمة في الذاكرة لتسريع أدائها ، وبالتالي اختار مؤلف الكود C بدلاً من C ++ يدعي أنه يمكن للمرء أن يصنع رمزًا أسرع وأكثر موثوقية (فيما يتعلق بتسربات الذاكرة) مع C.

هل توافق على ذلك؟ ماذا سيكون اختيارك ، إذا كنت بحاجة إلى تخزين 4-16 جيجابايت من صفائف البيانات في الذاكرة أثناء الحساب؟

هل كانت مفيدة؟

المحلول

بالتأكيد C ++. بشكل افتراضي ، لا يوجد فرق كبير بين الاثنين ، لكن يوفر C ++ بضعة أشياء لا:

  1. المنشئون/المدمرين. هذه تتيح لك أتمتة معظم إدارة الذاكرة ، وتحسين الموثوقية.
  2. مخصصات لكل فئة. هذه تتيح لك تحسين التخصيص بناءً على كيفية تصميم و/أو استخدام كائنات معينة. يمكن أن يكون هذا مفيدًا بشكل خاص إذا كنت بحاجة إلى عدد كبير من الكائنات الصغيرة (لإعطاء مثال واضح).

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

نصائح أخرى

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

إذا كان مؤلف الكود يمكن أن يوضح اختلاف الأداء بين كود C و C ++ الذي يخصص صفيف 4-16 جيجابايت ، فإن (أ) فوجئت ، لكن حسنًا ، هناك فرق ، و (ب) كم عددهم مرات هل سيقوم البرنامج بتخصيص مثل هذه المصفوفات الكبيرة؟ هل سيقضي برنامجك بالفعل قدرًا كبيرًا من وقته في تخصيص الذاكرة ، أم أنه يقضي معظم وقته الوصول الذاكرة والقيام بالحسابات؟ يستغرق وقتا طويلا في الواقع فعل أي شيء يحتوي على مجموعة 4 جيجابايت ، مقارنة بالوقت الذي استغرقته لتخصيصه ، وهذا يعني أنك يجب أن تكون قلقًا بشأن أداء "أي شيء" ، وليس أداء التخصيص. يهتم العداءون كثيرًا بالسرعة التي ينزلون بها. الماراثون المتسابقين ، وليس كثيرا.

عليك أيضًا أن تكون حذراً لكيفية القياس. يجب أن تقارن على سبيل المثال malloc(size) ضد new char[size]. إذا قمت باختبار malloc(size) ضد new char[size]() ثم إنها مقارنة غير عادلة لأن الأخير يحدد الذاكرة إلى 0 والآخر لا. قارن ضد calloc بدلاً من ذلك ، ولكن لاحظ ذلك أيضًا malloc و calloc كلاهما متاح من C ++ في الحدث (غير المحتمل) الذي يثبتانه بشكل أسرع بشكل ملموس.

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

لا يوجد فرق حقيقي بين C و C ++ من حيث تخصيص الذاكرة. يحتوي C ++ على المزيد من البيانات "المخفية" ، مثل المؤشرات الافتراضية وما إلى ذلك ، إذا اخترت أن يكون لديك طرق افتراضية على كائناتك. لكن تخصيص مجموعة من chars باهظة الثمن في C كما في C ++ ، في الواقع ، ربما يستخدمان Malloc للقيام بذلك. من حيث الأداء ، يستدعي C ++ مُنشئًا لكل كائن في الصفيف. لاحظ أن هذا يتم فقط إذا كان هناك واحد ، فإن المُنشئ الافتراضي لا يفعل شيئًا ويتم تحسينه بعيدًا.

طالما أنك تجمع بين البيانات المتوفرة ، لتجنب تجزئة الذاكرة ، يجب أن تكون على ما يرام. إذا كان لديك هيكل POD بسيط بدون طرق افتراضية ، وبدون مُنشئين ، فلا يوجد فرق.

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

اللغة ليست مشكلتك, ، تخصيص المصفوفات الكبيرة واضطرابها.

الخطأ الرئيسي المميت الذي يمكن أن ترتكبه في التخصيص (في أي من اللغة) هو تخصيص 16 جم من الذاكرة ، وتهيئتها إلى الصفر ، فقط لملء القيم الفعلية لاحقًا.

اكتساب معظم الأداء الذي أتوقعه من تحسينات الخوارزمية التي تعمل على تحسين موقع المرجع.

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

لتخصيص البيانات الأولية ، لا ينبغي أن يكون هناك فرق بين C و C ++ على معظم الأنظمة لأنها عادة ما تستخدم آليات مكتبة وقت التشغيل نفسها. أتساءل عما إذا كان هذا هو المأخير القياسي الكلاسيكي حيث قاموا أيضًا بقياس وقت تشغيل مكالمات المُنشئ في C ++ ونسيهم بشكل مناسب تضمين وقت تشغيل أي نوع من رمز التهيئة في C.

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

إن اهتماماتي الرئيسية بتخصيص الكثير من الذاكرة ستكون ذات شقين:

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

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

يمكنك استخدام عائلة C لوظائف تخصيص الذاكرة في C ++ أيضًا: كلا المعيار malloc و free, realloc لتكبير المصفوفات/القبيلة و alloca لتخصيص الذاكرة على المكدس.

إذا ذهبت مع new, ، سوف يخصص ذاكرة أكثر مما هو مطلوب (في الغالب أثناء تصحيح الأخطاء) وإجراء فحوصات إضافية للتناسق. كما سيتصل بمنشئ الفصول. في إصدار (-O3) بناء الفرق سيكون ضئيلًا لمعظم التطبيقات.

ماذا الآن new يجلب أن malloc لا هو في المكان new. يمكنك مضايقة المخزن المؤقت ثم استخدام الموقع new لوضع هيكلك في هذا المخزن المؤقت ، مما يجعل "تخصيص" فوريًا.

الكل في الكل ، لن أبتعد عن C بسبب مخاوف الأداء. إذا كان هناك أي شيء ، فسيكون الكود الخاص بك أكثر كفاءة لأن الفئات تمر this مؤشر في السجلات بدلا من المعلمات مثل في المكافئ C. سبب حقيقي للابتعاد عن C هو حجم وقت تشغيل C ++. إذا قمت بتطوير برامج للأنظمة المدمجة أو البرامج المحملة بالتمهيد ، فلن تتمكن من تضمين وقت تشغيل ~ 4 ميغابايت. بالنسبة للتطبيقات العادية ، لن يحدث هذا فرقًا.

إذا كنت بحاجة إلى تخزين 4-16 جيجابايت من صفائف البيانات في الذاكرة أثناء الحساب ولديه جهازك فقط 2 جيجابايت من الذاكرة الفعلية ، فماذا؟

ماذا لو كان لجهازك 16 جيجابايت من الذاكرة الفعلية؟ هل لا يتناول نظام التشغيل أي ذاكرة فعلية؟

هل يتيح لك نظام التشغيل حتى مساحة عنوان 4 جيجابايت ، 16 جيجابايت ، إلخ؟

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top