سؤال

أم أن الأمر الآن على العكس من ذلك؟

مما سمعته، هناك بعض المجالات التي تثبت فيها لغة C# أنها أسرع من لغة C++، ولكن لم تكن لدي الشجاعة لاختبارها بنفسي.

أعتقد أن أيًا منكم يمكنه شرح هذه الاختلافات بالتفصيل أو توجيهي إلى المكان الصحيح للحصول على معلومات حول هذا الموضوع.

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

المحلول

لا يوجد سبب صارم يمنع لغة تعتمد على الكود الثانوي مثل C# أو Java التي تحتوي على JIT من أن تكون بنفس سرعة كود C++.ومع ذلك، كان كود C++ أسرع بشكل ملحوظ لفترة طويلة، ولا يزال كذلك حتى اليوم في كثير من الحالات.ويرجع ذلك أساسًا إلى تعقيد تحسينات JIT الأكثر تقدمًا في التنفيذ، والتحسينات الرائعة حقًا لم تصل إلا الآن.

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

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

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

ضع في اعتبارك أنه من السهل نسبيًا تحسين برنامج صحيح، ولكن من الصعب جدًا تصحيح برنامج محسّن.

إن إعطاء نسب فعلية لمزايا السرعة أمر مستحيل، فهو يعتمد إلى حد كبير على الكود الخاص بك.في كثير من الحالات، لا يمثل تنفيذ لغة البرمجة حتى عنق الزجاجة.خذ المعايير في http://benchmarksgame.alioth.debian.org/ مع قدر كبير من الشك، حيث أن هذه التعليمات البرمجية الحسابية تختبر إلى حد كبير، والتي على الأرجح لا تشبه التعليمات البرمجية الخاصة بك على الإطلاق.

نصائح أخرى

قد لا تكون لغة C# أسرع، ولكنها تجعلك/أنا أسرع.هذا هو المقياس الأكثر أهمية لما أقوم به.:)

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

سأبدأ بالاختلاف مع جزء من الإجابة المقبولة (والتي تم التصويت عليها جيدًا) على هذا السؤال بالقول:

هناك بالفعل الكثير من الأسباب التي تجعل كود Jated يعمل أبطأ من برنامج C ++ المحسن بشكل صحيح (أو لغة أخرى بدون تكاليف وقت التشغيل) مشتمل:

  • دورات الحساب التي يتم إنفاقها على كود JITting في وقت التشغيل هي بحكم التعريف غير متاحة للاستخدام في تنفيذ البرنامج.

  • سوف تتنافس أي مسارات ساخنة في JITter مع التعليمات البرمجية الخاصة بك للتعليمات وذاكرة التخزين المؤقت للبيانات في وحدة المعالجة المركزية.نحن نعلم أن ذاكرة التخزين المؤقت تهيمن عندما يتعلق الأمر بالأداء وأن اللغات الأصلية مثل C++ لا تحتوي على هذا النوع من التنافس بحكم التعريف.

  • ميزانية الوقت لمحسن وقت التشغيل هي بالضرورة كثيراً أكثر تقييدًا من مُحسِّن وقت الترجمة (كما أشار معلق آخر)

الحد الأدنى:في نهاية المطاف، أنت سوف من المؤكد تقريبًا أن تكون قادرًا على إنشاء تطبيق أسرع في C++ مما يمكنك في C#.

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

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

--

فيما يتعلق بالأداء النسبي، فقد انزعجت أيضًا من الأرقام والمناقشات التي رأيتها في بعض الإجابات الأخرى، لذلك اعتقدت أنني سأشارك فيها وفي نفس الوقت، أقدم بعض الدعم للبيانات التي أدليت بها أعلاه.

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

بدلاً من ذلك، كتبت كود C++ اصطلاحيًا أكثر قليلًا وقارنته بكود C# المقدم من @Wiory.التغييران الرئيسيان اللذان أجريتهما على كود C++ هما:

1) ناقلات المستخدمة::احتياطي ()

2) قم بتسوية المصفوفة ثنائية الأبعاد إلى 1d لتحقيق مكان أفضل لذاكرة التخزين المؤقت (كتلة متجاورة)

سي# (.نت 4.6.1)

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);
}

وقت التشغيل (الإصدار):فيه:124 مللي ثانية، املأ:165 مللي ثانية

C++ 14 (كلانج v3.8/C2)

#include <iostream>
#include <vector>

auto TestSuite::ColMajorArray()
{
    constexpr size_t ROWS = 5000;
    constexpr size_t COLS = 9000;

    auto initStart = std::chrono::steady_clock::now();

    auto arr = std::vector<double>();
    arr.reserve(ROWS * COLS);

    auto initFinish = std::chrono::steady_clock::now();
    auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(initFinish - initStart);

    auto fillStart = std::chrono::steady_clock::now();

    for(auto i = 0, r = 0; r < ROWS; ++r)
    {
        for (auto c = 0; c < COLS; ++c)
        {
            arr[i++] = static_cast<double>(r * c);
        }
    }

    auto fillFinish = std::chrono::steady_clock::now();
    auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);

    return std::make_pair(initTime, fillTime);
}

وقت التشغيل (الإصدار):فيه:398 ثانية (نعم، هذا ميكروثانية)، املأ:152 مللي ثانية

إجمالي أوقات التشغيل:ج#:289 مللي ثانية، C++ 152 مللي ثانية (أسرع بنسبة 90% تقريبًا)

الملاحظات

  • تم تغيير تطبيق C# إلى نفس تطبيق صفيف 1D:40 مللي ثانية، املأ:171 مللي ثانية، الإجمالي:211 مللي ثانية (كان C ++ لا يزال أسرع بنسبة 40 ٪ تقريبًا).

  • يعد تصميم وكتابة التعليمات البرمجية "السريعة" في لغة C++ أصعب بكثير من كتابة التعليمات البرمجية "العادية" بأي من اللغتين.

  • (ربما) من السهل بشكل مدهش الحصول على أداء ضعيف في لغة C++؛لقد رأينا ذلك مع أداء المتجهات غير المحجوزة.وهناك الكثير من المزالق مثل هذا.

  • يعد أداء C# رائعًا إلى حد ما عندما تأخذ في الاعتبار كل ما يحدث في وقت التشغيل.وهذا الأداء سهل الوصول نسبيا.

  • المزيد من البيانات القصصية التي تقارن أداء C++ وC#: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore

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

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

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

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

أحد السيناريوهات المحددة التي لا تزال فيها اليد العليا لـ C++ (وسوف تستمر لسنوات قادمة) يحدث عندما يمكن تحديد القرارات متعددة الأشكال مسبقًا في وقت الترجمة.

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

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

في مثل هذه الحالات (ومن المسلم به أنها غالبًا ما تكون مقتصرة على مجالات مشاكل خاصة)، تفوز لغة C++ على لغة C# واللغات المماثلة.

يمنحك C++ (أو C في هذا الشأن) تحكمًا دقيقًا في هياكل البيانات الخاصة بك.إذا كنت ترغب في التلاعب، فلديك هذا الخيار.تطبيقات Java أو .NET الكبيرة المُدارة (OWB، فيجوال ستوديو 2005) التي تستخدم هياكل البيانات الداخلية لمكتبات Java/.NET تحمل الأمتعة معها.لقد شاهدت جلسات مصمم OWB تستخدم أكثر من 400 ميغابايت من ذاكرة الوصول العشوائي وعروض الأسعار للمكعب أو إيتل التصميم يصل إلى 100 ميغابايت أيضًا.

في حالة عبء العمل الذي يمكن التنبؤ به (مثل معظم المعايير التي تكرر العملية عدة مرات)، يمكن لـ JIT أن تحصل على تعليمات برمجية تم تحسينها بشكل جيد بما يكفي بحيث لا يوجد فرق عملي.

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

بالنسبة للرسومات، تعتبر فئة C# Graphics القياسية أبطأ بكثير من GDI التي يتم الوصول إليها عبر C/C++.أعلم أن هذا لا علاقة له باللغة في حد ذاتها، بل يتعلق أكثر بمنصة .NET الإجمالية، ولكن الرسومات هي ما يتم تقديمه للمطور كبديل لـ GDI، وأداءه سيء ​​للغاية لدرجة أنني لن أجرؤ حتى على عمل الرسومات معها.

لدينا معيار بسيط نستخدمه لمعرفة مدى سرعة مكتبة الرسومات، وهو ببساطة رسم خطوط عشوائية في النافذة.لا يزال C++/GDI سريعًا مع 10000 سطر بينما يواجه C#/Graphics صعوبة في تنفيذ 1000 سطر في الوقت الفعلي.

يعد تجميع البيانات المهملة هو السبب الرئيسي وراء عدم إمكانية استخدام Java# لأنظمة الوقت الفعلي.

  1. متى سيحدث GC؟

  2. كم من الوقت سوف يستغرق؟

هذا غير حتمية.

لقد كان علينا تحديد ما إذا كانت لغة C# قابلة للمقارنة مع لغة C++ في الأداء وقمت بكتابة بعض برامج الاختبار لذلك (باستخدام Visual Studio 2005 لكلا اللغتين).اتضح أنه بدون جمع البيانات المهملة والنظر فقط في اللغة (وليس إطار العمل)، تتمتع C# بنفس أداء C++.يعد تخصيص الذاكرة في C# أسرع بكثير من C++، كما أن C# لها ميزة طفيفة في الحتمية عند زيادة أحجام البيانات خارج حدود خط ذاكرة التخزين المؤقت.ومع ذلك، كان لا بد من دفع ثمن كل هذا في النهاية، وهناك تكلفة ضخمة في شكل نتائج أداء غير حتمية لـ C# بسبب جمع البيانات المهملة.

كالعادة، يعتمد الأمر على التطبيق.هناك حالات تكون فيها لغة C# أبطأ بشكل ملحوظ، وحالات أخرى تكون فيها لغة C++ أسرع بـ 5 أو 10 مرات، خاصة في الحالات التي يمكن فيها إجراء عملية SIMD بسهولة.

أعلم أن هذا ليس ما كنت تطلبه، ولكن لغة C# غالبًا ما تكون أسرع في ذلك يكتب من C++، وهي مكافأة كبيرة في بيئة تجارية.

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

تكون مكافآت C/C++ أكثر وضوحًا إذا التزمت مباشرة بالمؤشرات وتجنبت Boost، std::vector وغيرها من الحاويات عالية المستوى، كذلك inline كل وظيفة صغيرة ممكنة.استخدم صفائف المدرسة القديمة كلما أمكن ذلك.نعم، ستحتاج إلى المزيد من أسطر التعليمات البرمجية لإنجاز نفس الشيء الذي فعلته في Java أو C# مع تجنب الحاويات عالية المستوى.إذا كنت بحاجة إلى مصفوفة ذات حجم ديناميكي، فستحتاج فقط إلى تذكر إقران ملفك new T[] مع المقابلة delete[] بيان (أو استخدام std::unique_ptr) - ثمن السرعة الإضافية هو أنه يجب عليك البرمجة بعناية أكبر.ولكن في المقابل، يمكنك التخلص من الحمل الزائد للذاكرة المُدارة/أداة تجميع البيانات المهملة، والتي يمكن بسهولة أن تصل إلى 20% أو أكثر من وقت تنفيذ البرامج شديدة التوجه للكائنات في كل من Java و.NET، بالإضافة إلى تلك البرامج الضخمة المُدارة تكاليف فهرسة مجموعة الذاكرة.يمكن أن تستفيد تطبيقات C++ أيضًا من بعض مفاتيح التحويل البرمجي الأنيقة في بعض الحالات المحددة.

أنا مبرمج خبير في C وC++ وJava وC#.لقد أتيحت لي مؤخرًا فرصة نادرة لتنفيذ نفس البرنامج الخوارزمي باللغات الثلاث الأخيرة.كان لدى البرنامج الكثير من العمليات الحسابية والمصفوفات متعددة الأبعاد.لقد قمت بتحسين هذا بشكل كبير في جميع اللغات الثلاث. كانت النتائج نموذجية لما أراه عادةً في مقارنات أقل صرامة:كانت Java أسرع بحوالي 1.3x من C# (معظم JVMs أكثر تحسينًا من CLR)، وجاء إصدار المؤشر الخام لـ C++ أسرع بحوالي 2.1x من C#. لاحظ أن برنامج C# يستخدم كودًا آمنًا فقط، ومن رأيي أنه من الأفضل أن تقوم بترميزه في C++ قبل استخدام البرنامج. unsafe الكلمة الرئيسية.

حتى لا يظن أي شخص أن لدي شيئًا ضد لغة C#، سأختتم بالقول إن لغة C# هي على الأرجح لغتي المفضلة.إنها لغة التطور الأكثر منطقية وبديهية وسرعة التي واجهتها حتى الآن.أفعل كل ما عندي من النماذج الأولية في C #.تتمتع لغة C# بالعديد من المزايا الصغيرة والدقيقة مقارنة بـ Java (نعم، أعلم أن Microsoft حظيت بفرصة إصلاح العديد من عيوب Java عن طريق الدخول إلى اللعبة متأخرًا ونسخ Java على الأرجح).نخب جافا Calendar فئة أي شخص؟إذا بذلت Microsoft مجهودًا حقيقيًا لتحسين CLR و.NET JITter، فقد تتولى لغة C# المهمة بجدية.أنا مندهش بصراحة أنهم لم يفعلوا ذلك بالفعل - لقد فعلوا الكثير من الأشياء بشكل صحيح في لغة C#، فلماذا لا يتبعونها بتحسينات شديدة التأثير للمترجم؟ربما لو توسلنا جميعا.

> مما سمعته..

يبدو أن الصعوبة التي تواجهك تكمن في تحديد ما إذا كان ما سمعته ذا مصداقية، وسوف تتكرر هذه الصعوبة عندما تحاول تقييم الردود على هذا الموقع.

كيف ستقرر ما إذا كانت الأشياء التي يقولها الناس هنا أكثر أو أقل مصداقية مما سمعته في الأصل؟

إحدى الطرق هي أن تطلب شهادة.

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

غالبًا ما يتم الخلط بين المعلومات والآراء فيما يدعيه الناس، وسيتعين عليك محاولة تحديد أي منهما.على سبيل المثال، من الردود في هذا المنتدى:

  • "خذ المعايير في http://shootout.alioth.debian.org/مع قدر كبير من الشكوك ، حيث أن هذه الكود الحساب إلى حد كبير ، والتي لا تشبه على الأرجح رمزك على الإطلاق. "

    اسأل نفسك إذا كنت تفهم حقًا ماذا "هذه الكود الحساب إلى حد كبير" يعني ، ثم اسأل نفسك عما إذا كان المؤلف قد أظهر لك بالفعل أن ادعائه صحيح.

  • "هذا اختبار عديم الفائدة إلى حد ما ، لأنه يعتمد حقًا على مدى جودة البرامج الفردية ؛لقد تمكنت من تسريع بعضها بمقدار 4-6 مرات أو أكثر ، مما أوضح أن المقارنة بين البرامج غير المستقرة سخيفة إلى حد ما. "

    اسأل نفسك ما إذا كان المؤلف قد أظهر لك فعليًا أنه تمكن من "تسريع بعضها بمقدار 4-6 مرات أو أكثر" - إنه مطالبة سهلة!

يمكن أن تكون لغات .NET بنفس سرعة كود C++، أو حتى أسرع، لكن كود C++ سيكون له إنتاجية أكثر ثباتًا نظرًا لأن وقت تشغيل .NET يجب أن يتوقف مؤقتًا جي سي, ، حتى لو كان ذكيًا جدًا في توقفاته المؤقتة.

لذلك، إذا كان لديك بعض التعليمات البرمجية التي يجب أن تعمل بسرعة باستمرار دون أي توقف مؤقت، فسوف يقدم .NET زمن الوصول في مرحلة ما, ، حتى لو كنت حريصًا جدًا على وقت تشغيل GC.

بالنسبة للمشكلات "المتوازية بشكل محرج"، عند استخدام Intel TBB وOpenMP على C++، لاحظت زيادة في الأداء بمقدار 10 أضعاف تقريبًا مقارنة بالمشكلات المماثلة (الرياضيات البحتة) التي تم إجراؤها باستخدام C# وTPL.SIMD هو أحد المجالات التي لا يمكن لـ C# التنافس فيها، ولكن لدي أيضًا انطباع بأن TPL لديها نفقات عامة كبيرة.

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

إنه سؤال غامض للغاية دون إجابات محددة حقيقية.

على سبيل المثال؛أفضل أن ألعب الألعاب ثلاثية الأبعاد التي تم إنشاؤها بلغة C++ بدلاً من C#، لأن الأداء أفضل كثيرًا بالتأكيد.(وأنا أعرف XNA، وما إلى ذلك، لكنه لا يقترب بأي حال من الأحوال من الشيء الحقيقي).

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

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

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

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

لقد اختبرت vector في C++ وC# المكافئة - List ومصفوفات ثنائية الأبعاد بسيطة.

أنا أستخدم إصدارات Visual C#/C++ 2010 Express.كلا المشروعين عبارة عن تطبيقات وحدة تحكم بسيطة، لقد قمت باختبارهما في الإصدار القياسي (بدون إعدادات مخصصة) ووضع التصحيح.تعمل قوائم C# بشكل أسرع على جهاز الكمبيوتر الخاص بي، وتكون تهيئة المصفوفة أسرع أيضًا في C#، وتكون العمليات الحسابية أبطأ.

أنا أستخدم Intel Core2Duo P8600@2.4 جيجا هرتز، C# - .NET 4.0.

أعلم أن تطبيق المتجهات يختلف عن قائمة C#، ولكني أردت فقط اختبار المجموعات التي سأستخدمها لتخزين كائناتي (والقدرة على استخدام موصل الفهرس).

بالطبع تحتاج إلى مسح الذاكرة (دعنا نقول لكل استخدام لـ new)، ولكني أردت أن أبقي الكود بسيطًا.

اختبار ناقلات C++:

static void TestVector()
{
    clock_t start,finish;
    start=clock();
    vector<vector<double>> myList=vector<vector<double>>();
    int i=0;
    for( i=0; i<500; i++)
    {
        myList.push_back(vector<double>());
        for(int j=0;j<50000;j++)
            myList[i].push_back(j+i);
    }
    finish=clock();
    cout<<(finish-start)<<endl;
    cout<<(double(finish - start)/CLOCKS_PER_SEC);
}

اختبار قائمة C#:

private static void TestVector()
{

    DateTime t1 = System.DateTime.Now;
    List<List<double>> myList = new List<List<double>>();
    int i = 0;
    for (i = 0; i < 500; i++)
    {
        myList.Add(new List<double>());
        for (int j = 0; j < 50000; j++)
            myList[i].Add(j *i);
    }
    DateTime t2 = System.DateTime.Now;
    Console.WriteLine(t2 - t1);
}

C++ - المصفوفة:

static void TestArray()
{
    cout << "Normal array test:" << endl;
    const int rows = 5000;
    const int columns = 9000;
    clock_t start, finish;

    start = clock();
    double** arr = new double*[rows];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    finish = clock();

    cout << (finish - start) << endl;

    start = clock();
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    finish = clock();

    cout << (finish - start) << endl;
}

C# - المصفوفة:

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

}

وقت:(الإصدار/التصحيح)

سي ++

  • 600/606 مللي ثانية مجموعة init،
  • تعبئة مصفوفة 200/270 مللي ثانية،
  • 1 ثانية / 13 ثانية متجه للتهيئة والتعبئة.

(نعم، 13 ثانية، أواجه دائمًا مشكلات مع القوائم/المتجهات في وضع التصحيح.)

ج#:

  • 20/20 مللي ثانية مجموعة init،
  • 403/440 مللي تعبئة المصفوفة،
  • 710 / 742 مللي قائمة التهيئة والتعبئة.

حسنا، هذا يعتمد.إذا تمت ترجمة كود البايت إلى كود الآلة (وليس JIT فقط) (أعني إذا قمت بتنفيذ البرنامج) و إذا كان برنامجك يستخدم العديد من عمليات التخصيص/إلغاء التخصيص، فقد يكون أسرع لأن جي سي تحتاج الخوارزمية فقط إلى مرور واحد (نظريًا) عبر الذاكرة بأكملها مرة واحدة، ولكن مكالمات malloc/realloc/free C/C++ العادية تتسبب في زيادة الحمل على كل مكالمة (الحمل الزائد للمكالمات، والحمل الزائد لبنية البيانات، وذاكرة التخزين المؤقت المفقودة؛)).

لذلك فمن الممكن من الناحية النظرية (أيضًا للغات GC الأخرى).

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

ميزة كبيرة أخرى هي أن SQL، مثل لينك يوفر "الامتداد" فرصًا للمترجم لتحسين الاستدعاءات لقواعد البيانات (وبعبارة أخرى، يمكن للمترجم تجميع LINQ بالكامل إلى ثنائي "blob" واحد حيث تكون الوظائف المطلوبة مضمنة أو لاستخدامك الأمثل، لكنني أتكهن هنا ).

أفترض أن هناك تطبيقات مكتوبة بلغة C# تعمل بسرعة، بالإضافة إلى أن هناك المزيد من التطبيقات المكتوبة بلغة C++ تعمل بسرعة (حسنًا C++ أقدم فقط ...وخذ UNIX أيضًا ...)
- السؤال هو بالفعل - ما هو الشيء الذي يشتكي منه المستخدمون والمطورون ...
حسنًا، IMHO، في حالة C#، لدينا واجهة مستخدم مريحة جدًا، وتسلسل هرمي لطيف جدًا للمكتبات، ونظام واجهة كامل لـ CLI.في حالة C++، لدينا قوالب، ATL، COM، MFC وshebang بالكامل من التعليمات البرمجية المكتوبة والتشغيلية بالفعل مثل OpenGL وDirectX وما إلى ذلك...يشكو المطورون من ارتفاع مكالمات GC بشكل غير محدد في حالة C# (يعني أن البرنامج يعمل بسرعة، وفي ثانية واحدة - فرقعة!إنه عالق).
إن كتابة التعليمات البرمجية في C# بسيطة جدًا وسريعة (لا تنس أن ذلك يزيد أيضًا من احتمال حدوث أخطاء.في حالة C++، يشكو المطورون من تسرب الذاكرة، - يعني السحق، والمكالمات بين ملفات DLL، بالإضافة إلى "DLL hell" - مشكلة في دعم المكتبات واستبدالها بمكتبات أحدث...
أعتقد أنه كلما زادت مهاراتك في لغة البرمجة، كلما زادت الجودة (والسرعة) التي تميز برنامجك.

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

> بعد كل شيء، يجب أن تكون الإجابات موجودة في مكان ما، أليس كذلك؟:)

أم لا.

كما لاحظت عدة ردود السؤال غير محدد بطرق تثير أسئلة في الرد، وليس إجابات.لاتخاذ طريقة واحدة فقط:

ثم أي برامج؟أي آلة؟أي نظام تشغيل؟أي مجموعة بيانات؟

إذا لم أكن مخطئا، يتم تحديد قوالب C# في وقت التشغيل.يجب أن يكون هذا أبطأ من قوالب وقت الترجمة لـ C++.

وعندما تأخذ في الاعتبار جميع تحسينات وقت الترجمة الأخرى التي ذكرها العديد من الآخرين، بالإضافة إلى الافتقار إلى الأمان الذي يعني بالفعل المزيد من السرعة...

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

الحكم:

  • ج#:تطور أسرع، تشغيل أبطأ

  • ج++:تطور بطيء، تشغيل أسرع.

يعتمد الأمر حقًا على ما تحاول تحقيقه في التعليمات البرمجية الخاصة بك.لقد سمعت أنه من الأساطير الحضرية أن هناك أي اختلاف في الأداء بين VB.NET وC# وC++ المُدارة.ومع ذلك، فقد وجدت، على الأقل في مقارنات السلاسل، أن لغة C++ المُدارة تتفوق على لغة C#، والتي بدورها تتفوق على لغة VB.NET.

لم أقم بأي حال من الأحوال بأي مقارنات شاملة في التعقيد الخوارزمي بين اللغات.أنا أيضًا أستخدم الإعدادات الافتراضية في كل لغة من اللغات.في VB.NET أستخدم الإعدادات للمطالبة بإعلان المتغيرات، وما إلى ذلك.إليك الكود الذي أستخدمه لـ C++ المُدار:(كما ترون، هذا الرمز بسيط للغاية).أنا أقوم بتشغيل نفس الشيء باللغات الأخرى في Visual Studio 2013 مع .NET 4.6.2.

#include "stdafx.h"

using namespace System;
using namespace System::Diagnostics;

bool EqualMe(String^ first, String^ second)
{
    return first->Equals(second);
}
int main(array<String ^> ^args)
{
    Stopwatch^ sw = gcnew Stopwatch();
    sw->Start();
    for (int i = 0; i < 100000; i++)
    {
        EqualMe(L"one", L"two");
    }
    sw->Stop();
    Console::WriteLine(sw->ElapsedTicks);
    return 0;
}

هناك بعض الاختلافات الرئيسية بين C# وC++ من حيث الأداء:

  • C# يعتمد على GC/الكومة.يعد التخصيص وGC نفسه بمثابة حمل غير محلي للوصول إلى الذاكرة
  • لقد أصبح مُحسِّنو C++ جيدين جدًا على مر السنين.لا يمكن لمترجمي JIT تحقيق نفس المستوى نظرًا لأن وقت الترجمة لديهم محدود فقط ولا يرون النطاق العالمي

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

ومن هذا المنطلق، قمت بإجراء اختبار سريع بنسبة 60 بالمائة من التعليمات الشائعة المطلوبة في معظم البرامج.

إليك رمز C#:

for (int i=0; i<1000; i++)
{
    StreamReader str = new StreamReader("file.csv");
    StreamWriter stw = new StreamWriter("examp.csv");
    string strL = "";
    while((strL = str.ReadLine()) != null)
    {
        ArrayList al = new ArrayList();
        string[] strline = strL.Split(',');
        al.AddRange(strline);
        foreach(string str1 in strline)
        {
            stw.Write(str1 + ",");
        }
        stw.Write("\n");
    }
    str.Close();
    stw.Close();
}

يتم استخدام مصفوفة السلسلة وقائمة المصفوفات بشكل مقصود لتضمين تلك التعليمات.

إليك كود c++:

for (int i = 0; i<1000; i++)
{
    std::fstream file("file.csv", ios::in);
    if (!file.is_open())
    {
        std::cout << "File not found!\n";
        return 1;
    }

    ofstream myfile;
    myfile.open ("example.txt");
    std::string csvLine;

    while (std::getline(file, csvLine))
    {
        std::istringstream csvStream(csvLine);
        std::vector csvColumn;
        std::string csvElement;

        while( std::getline(csvStream, csvElement, ‘,’) )
        {
            csvColumn.push_back(csvElement);
        }

        for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
        {
            myfile << *j << ", ";
        }

        csvColumn.clear();
        csvElement.clear();
        csvLine.clear();
        myfile << "\n";
    }
    myfile.close();
    file.close();
}

كان حجم ملف الإدخال الذي استخدمته هو 40 كيلوبايت.

وها هي النتيجة -

  • تم تشغيل كود C++ في 9 ثوانٍ.
  • كود سي#:4 ثواني!!!

أوه، ولكن هذا كان على لينكس ...مع تشغيل C# كثرة الوحيدات...وC++ مع g++.

حسنًا، هذا ما حصلت عليه على Windows – فيجوال ستوديو 2003:

  • تم تشغيل كود C# خلال 9 ثوانٍ.
  • كود C++ - 370 ثانية فظيعة !!!
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top