C ++ की तुलना में D कितना तेज है?


133

मुझे D के कुछ फीचर्स पसंद हैं, लेकिन अगर वे रनटाइम पेनल्टी के साथ आते हैं, तो क्या मुझे दिलचस्पी होगी?

तुलना करने के लिए, मैंने एक साधारण प्रोग्राम लागू किया जो C ++ और D. दोनों में कई छोटे वैक्टर के स्केलर उत्पादों की गणना करता है। परिणाम आश्चर्यजनक है:

  • D: 18.9 s [अंतिम रनटाइम के लिए नीचे देखें]
  • सी ++: 3.8 एस

क्या सी ++ वास्तव में लगभग पांच गुना तेज है या मैंने डी कार्यक्रम में गलती की है?

मैंने C ++ को g ++ -O3 (gcc-snapshot 2011-02-19) और D के साथ dmd -O (dmd 2.052) एक मध्यम हाल के लिनक्स डेस्कटॉप पर संकलित किया। परिणाम कई रन और मानक विचलन नगण्य पर प्रतिलिपि प्रस्तुत करने योग्य हैं।

यहाँ C ++ प्रोग्राम:

#include <iostream>
#include <random>
#include <chrono>
#include <string>

#include <vector>
#include <array>

typedef std::chrono::duration<long, std::ratio<1, 1000>> millisecs;
template <typename _T>
long time_since(std::chrono::time_point<_T>& time) {
      long tm = std::chrono::duration_cast<millisecs>( std::chrono::system_clock::now() - time).count();
  time = std::chrono::system_clock::now();
  return tm;
}

const long N = 20000;
const int size = 10;

typedef int value_type;
typedef long long result_type;
typedef std::vector<value_type> vector_t;
typedef typename vector_t::size_type size_type;

inline value_type scalar_product(const vector_t& x, const vector_t& y) {
  value_type res = 0;
  size_type siz = x.size();
  for (size_type i = 0; i < siz; ++i)
    res += x[i] * y[i];
  return res;
}

int main() {
  auto tm_before = std::chrono::system_clock::now();

  // 1. allocate and fill randomly many short vectors
  vector_t* xs = new vector_t [N];
  for (int i = 0; i < N; ++i) {
    xs[i] = vector_t(size);
      }
  std::cerr << "allocation: " << time_since(tm_before) << " ms" << std::endl;

  std::mt19937 rnd_engine;
  std::uniform_int_distribution<value_type> runif_gen(-1000, 1000);
  for (int i = 0; i < N; ++i)
    for (int j = 0; j < size; ++j)
      xs[i][j] = runif_gen(rnd_engine);
  std::cerr << "random generation: " << time_since(tm_before) << " ms" << std::endl;

  // 2. compute all pairwise scalar products:
  time_since(tm_before);
  result_type avg = 0;
  for (int i = 0; i < N; ++i)
    for (int j = 0; j < N; ++j) 
      avg += scalar_product(xs[i], xs[j]);
  avg = avg / N*N;
  auto time = time_since(tm_before);
  std::cout << "result: " << avg << std::endl;
  std::cout << "time: " << time << " ms" << std::endl;
}

और यहाँ डी संस्करण:

import std.stdio;
import std.datetime;
import std.random;

const long N = 20000;
const int size = 10;

alias int value_type;
alias long result_type;
alias value_type[] vector_t;
alias uint size_type;

value_type scalar_product(const ref vector_t x, const ref vector_t y) {
  value_type res = 0;
  size_type siz = x.length;
  for (size_type i = 0; i < siz; ++i)
    res += x[i] * y[i];
  return res;
}

int main() {   
  auto tm_before = Clock.currTime();

  // 1. allocate and fill randomly many short vectors
  vector_t[] xs;
  xs.length = N;
  for (int i = 0; i < N; ++i) {
    xs[i].length = size;
  }
  writefln("allocation: %i ", (Clock.currTime() - tm_before));
  tm_before = Clock.currTime();

  for (int i = 0; i < N; ++i)
    for (int j = 0; j < size; ++j)
      xs[i][j] = uniform(-1000, 1000);
  writefln("random: %i ", (Clock.currTime() - tm_before));
  tm_before = Clock.currTime();

  // 2. compute all pairwise scalar products:
  result_type avg = cast(result_type) 0;
  for (int i = 0; i < N; ++i)
    for (int j = 0; j < N; ++j) 
      avg += scalar_product(xs[i], xs[j]);
  avg = avg / N*N;
  writefln("result: %d", avg);
  auto time = Clock.currTime() - tm_before;
  writefln("scalar products: %i ", time);

  return 0;
}

3
वैसे, आपके प्रोग्राम में इस लाइन पर एक बग है: avg = avg / N*N(संचालन का क्रम)।
व्लादिमीर पेंटेलेव

4
आप सरणी / वेक्टर आपरेशन का उपयोग कर कोड को फिर से लिखने की कोशिश कर सकते digitalmars.com/d/2.0/arrays.html
मीकल Minich

10
एक बेहतर तुलना प्रदान करने के लिए आपको समान संकलक बैक-एंड का उपयोग करना चाहिए। या तो DMD और DMC ++ या GDC और G ++
he_the_great

1
@ सायन शेवोक दुर्भाग्य से, डीएमडी प्रोफाइलिंग लिनक्स के लिए उपलब्ध नहीं लगती है? (कृपया मुझे सही कर अगर मैं गलत हूँ, लेकिन अगर मैं कहता हूँ dmd ... trace.defमैं एक मिल error: unrecognized file extension defऔर के लिए डीएमडी डॉक्स। optlink उल्लेख केवल Windows।
लार्स

1
आह, उस .def फ़ाइल के बारे में कभी ध्यान नहीं दिया। समय .log फ़ाइल के अंदर हैं। "इसमें फ़ंक्शंस की सूची होती है, जिस क्रम में लिंकर को उन्हें लिंक करना चाहिए" - हो सकता है कि ऑप्टिक्लिंक किसी चीज़ को ऑप्टिमाइज़ करने में मदद करता हो? यह भी ध्यान दें कि "इसके अलावा, ld मानक" * .def "फाइलों का पूरी तरह से समर्थन करता है, जो कि ऑब्जेक्ट फाइल की तरह लिंकर कमांड लाइन पर निर्दिष्ट किया जा सकता है" - इसलिए आप ट्रेस पास कर सकते हैं। यदि आप प्रिय चाहते हैं तो -L से गुजरें। सेवा।
Trass3r

जवाबों:


64

सभी अनुकूलन को सक्षम करने और सभी सुरक्षा जांच को अक्षम करने के लिए, अपने डी कार्यक्रम को निम्नलिखित डीएमडी झंडे के साथ संकलित करें:

-O -inline -release -noboundscheck

संपादित करें : मैंने आपके कार्यक्रमों को g ++, dmd और gdc के साथ आज़माया है। dmd पिछड़ जाता है, लेकिन gdc g ++ के बहुत करीब प्रदर्शन प्राप्त करता है। मैंने जो कमांडलाइन का उपयोग किया था gdmd -O -release -inline(gdmd gdc के आसपास एक आवरण है जो dmd विकल्पों को स्वीकार करता है)।

कोडांतरक लिस्टिंग को देखते हुए, ऐसा लगता है कि न तो dmd और न ही gdc इनलाइन है scalar_product, लेकिन g ++ / gdc ने MMX निर्देशों का उत्सर्जन किया, इसलिए वे लूप को ऑटो- वेक्टर कर सकते हैं।


3
@CyberShadow: लेकिन अगर आप सुरक्षा जांच को हटा देते हैं ... तो क्या आप D की कुछ महत्वपूर्ण विशेषताओं को नहीं खो रहे हैं?
मथिउ एम।

33
आप उन सुविधाओं को खो रहे हैं जो C ++ में कभी नहीं थी। अधिकांश भाषाएं आपको विकल्प नहीं देती हैं।
व्लादिमीर पेंटेलेव

6
@CyberShadow: क्या हम इसे डीबग बनाम रिलीज़ बिल्ड के एक प्रकार के रूप में सोच सकते हैं?
फ्रांसेस्को

7
@ बर्नार्ड: -रेल में, सुरक्षित कार्यों को छोड़कर सभी कोड के लिए बाउंड चेकिंग बंद है। वास्तव में सीमा की जाँच करने के लिए -release और noboundscheck दोनों का उपयोग करें।
मिशाल मिनिच

5
@CyberShadow धन्यवाद! इन झंडों के साथ रनटाइम में काफी सुधार होता है। अब D 12.9 s पर है। लेकिन फिर भी लंबे समय तक 3 से अधिक बार चलता है। @ मैथ्यू एम। मैं किसी कार्यक्रम को धीमी गति में बाउंडकचिंग के साथ परीक्षण करने के लिए बुरा नहीं मानूंगा और एक बार डिबग किए जाने के बाद यह बिना कंपाउंडिंग किए अपनी गणना करने दें। (मैं अब सी ++ के साथ भी ऐसा ही करता हूं।)
लार्स

32

डी डाउन को धीमा करने वाली एक बड़ी चीज एक सबपर कचरा संग्रहण कार्यान्वयन है। बेंचमार्क जो भारी तनाव नहीं करते हैं, जीसी सी और सी ++ कोड के समान प्रदर्शन को उसी संकलक बैकएंड के साथ संकलित करेंगे। जीसी पर जोर देने वाले बेंचमार्क यह दर्शाएंगे कि डी असामान्य रूप से प्रदर्शन करता है। बाकी का आश्वासन दिया गया है, हालांकि, यह एक एकल (यद्यपि गंभीर) गुणवत्ता-के-कार्यान्वयन का मुद्दा है, न कि दासता की गारंटी देने वाला। इसके अलावा, D आपको प्रदर्शन-क्रिटिकल बिट्स में GC और ट्यून मेमोरी मैनेजमेंट से बाहर निकलने की क्षमता देता है, जबकि अभी भी इसे कम परफॉर्मेंस-क्रिटिकल 95% कोड में इस्तेमाल किया जाता है।

मैंने जीसी प्रदर्शन को बेहतर बनाने के लिए कुछ प्रयास किए हैं और परिणाम नाटकीय रूप से कम से कम सिंथेटिक बेंचमार्क पर आए हैं। उम्मीद है कि इन परिवर्तनों को अगले कुछ रिलीज में से एक में एकीकृत किया जाएगा और इस मुद्दे को कम करेगा।


1
मैंने देखा कि आपका एक परिवर्तन विभाजन से बिट शिफ्ट में बदलाव था। नहीं होना चाहिए कि कुछ संकलक करता है?
GManNickG

3
@ मन: हां, यदि आप जिस मूल्य को विभाजित कर रहे हैं वह संकलन समय पर जाना जाता है। नहीं, यदि मूल्य केवल रनटाइम पर जाना जाता है, तो यही वह स्थिति थी जहां मैंने उस अनुकूलन को बनाया था।
dsimcha

@dsimcha: एचएम। मुझे पता है कि अगर आप इसे बनाना जानते हैं, तो कंपाइलर भी बना सकता है। कार्यान्वयन के मुद्दे की गुणवत्ता, या मुझे याद आ रही है कि कुछ शर्त को संतुष्ट करने की आवश्यकता है कि संकलक साबित नहीं हो सकता है, लेकिन आप जानते हैं? (मैं अभी डी सीख रहा हूं, इसलिए कंपाइलर के बारे में ये छोटी बातें मेरे लिए अचानक दिलचस्प हैं। :))
GManNickG

13
@ मन: बिट शिफ्टिंग केवल तभी काम करती है जब आप जिस संख्या को विभाजित कर रहे हैं वह दो की शक्ति है। संकलक यह साबित नहीं कर सकता है यदि संख्या को केवल रनटाइम पर जाना जाता है, और परीक्षण और ब्रांचिंग डिव निर्देश का उपयोग करने की तुलना में धीमा होगा। मेरा मामला असामान्य है क्योंकि मूल्य केवल रनटाइम पर जाना जाता है, लेकिन मैं संकलन समय पर जानता हूं कि यह दो की कुछ शक्ति होने जा रही है।
dsimcha

7
ध्यान दें कि इस उदाहरण में पोस्ट किया गया प्रोग्राम समय लेने वाले हिस्से में आवंटन नहीं करता है।
व्लादिमीर पेंटेलेव

27

यह एक बहुत ही शिक्षाप्रद सूत्र है, ओपी और सहायकों के सभी कार्यों के लिए धन्यवाद।

एक नोट - यह परीक्षण अमूर्त / सुविधा जुर्माना या यहां तक ​​कि बैकएंड की गुणवत्ता के सामान्य प्रश्न का आकलन नहीं कर रहा है। यह वस्तुतः एक अनुकूलन (लूप अनुकूलन) पर केंद्रित है। मुझे लगता है कि यह कहना उचित है कि gcc का बैकएंड dmd की तुलना में कुछ अधिक परिष्कृत है, लेकिन यह मान लेना एक गलती होगी कि उनके बीच का अंतर सभी कार्यों के लिए उतना ही बड़ा है।


4
मैं पूरी तरह से सहमत। जैसा कि बाद में जोड़ा गया, मैं संख्यात्मक अभिकलन के लिए मुख्य रूप से प्रदर्शन में दिलचस्पी रखता हूं जहां लूप ऑप्टिमाइज़ेशन शायद सबसे महत्वपूर्ण है। आपको लगता है कि संख्यात्मक कंप्यूटिंग के लिए कौन से अन्य अनुकूलन होंगे? और कौन सी संगणना उनका परीक्षण करेगी? मुझे अपने परीक्षण के पूरक और कुछ और परीक्षणों को लागू करने में दिलचस्पी होगी (यदि वे लगभग सरल हैं)। लेकिन बेदखल। यह अपने आप में एक और सवाल है?
लार्स

11
एक इंजीनियर के रूप में जिसने C ++ पर अपने दांत काट लिए, आप मेरे एक हीरो हैं। सम्मानपूर्वक, हालाँकि, यह एक टिप्पणी होनी चाहिए, एक उत्तर नहीं।
एलन

14

निश्चित रूप से एक गुणवत्ता-कार्यान्वयन के मुद्दे की तरह लगता है।

मैंने ओपी के कोड के साथ कुछ परीक्षण चलाए और कुछ बदलाव किए। मुझे वास्तव में D LDC / clang ++ के लिए तेजी से जा रहा है , इस धारणा पर काम कर रहा है कि सरणियों को गतिशील रूप से ( xsऔर संबद्ध स्केलिंग) आवंटित किया जाना चाहिए । कुछ नंबरों के लिए नीचे देखें।

ओपी के लिए प्रश्न

क्या यह जानबूझकर है कि सी ++ के प्रत्येक पुनरावृत्ति के लिए एक ही बीज का उपयोग किया जाए, जबकि डी के लिए ऐसा नहीं है?

सेट अप

मैंने मूल डी स्रोत को ट्वीड किया है scalar.d प्लेटफार्मों के बीच इसे पोर्टेबल बनाने के ) को ट्विस्ट किया है। इसमें केवल सरणियों के आकार तक पहुंचने और संशोधित करने के लिए उपयोग किए जाने वाले संख्याओं के प्रकार को शामिल करना शामिल था।

इसके बाद, मैंने निम्नलिखित बदलाव किए:

  • uninitializedArrayXs में स्केलर के लिए डिफ़ॉल्ट इनिट्स से बचने के लिए उपयोग किया जाता है (शायद सबसे बड़ा अंतर)।यह महत्वपूर्ण है क्योंकि डी सामान्य रूप से सब कुछ चुपचाप निष्क्रिय कर देता है, जो सी ++ नहीं करता है।

  • प्रिंटिंग कोड से बाहर कर दिया गया और उसके writeflnसाथ बदल दिया गयाwriteln

  • चयनात्मक होने के लिए आयात को बदला गया
  • ^^गणना की औसत के अंतिम चरण के लिए मैनुअल गुणा के बजाय प्रयुक्त पाउ ऑपरेटर ( )
  • हटा दिया गया size_typeऔर नए index_typeउपनाम के साथ उचित रूप से बदल दिया गया

... इस प्रकार scalar2.cpp( pastebin ):

    import std.stdio : writeln;
    import std.datetime : Clock, Duration;
    import std.array : uninitializedArray;
    import std.random : uniform;

    alias result_type = long;
    alias value_type = int;
    alias vector_t = value_type[];
    alias index_type = typeof(vector_t.init.length);// Make index integrals portable - Linux is ulong, Win8.1 is uint

    immutable long N = 20000;
    immutable int size = 10;

    // Replaced for loops with appropriate foreach versions
    value_type scalar_product(in ref vector_t x, in ref vector_t y) { // "in" is the same as "const" here
      value_type res = 0;
      for(index_type i = 0; i < size; ++i)
        res += x[i] * y[i];
      return res;
    }

    int main() {
      auto tm_before = Clock.currTime;
      auto countElapsed(in string taskName) { // Factor out printing code
        writeln(taskName, ": ", Clock.currTime - tm_before);
        tm_before = Clock.currTime;
      }

      // 1. allocate and fill randomly many short vectors
      vector_t[] xs = uninitializedArray!(vector_t[])(N);// Avoid default inits of inner arrays
      for(index_type i = 0; i < N; ++i)
        xs[i] = uninitializedArray!(vector_t)(size);// Avoid more default inits of values
      countElapsed("allocation");

      for(index_type i = 0; i < N; ++i)
        for(index_type j = 0; j < size; ++j)
          xs[i][j] = uniform(-1000, 1000);
      countElapsed("random");

      // 2. compute all pairwise scalar products:
      result_type avg = 0;
      for(index_type i = 0; i < N; ++i)
        for(index_type j = 0; j < N; ++j)
          avg += scalar_product(xs[i], xs[j]);
      avg /= N ^^ 2;// Replace manual multiplication with pow operator
      writeln("result: ", avg);
      countElapsed("scalar products");

      return 0;
    }

परीक्षण के बाद scalar2.d(जो गति के लिए अनुकूलन को प्राथमिकता देता है), जिज्ञासा से बाहर मैंने छोरों mainको foreachसमकक्षों के साथ बदल दिया , और इसे scalar3.d( पास्टबिन ) कहा :

    import std.stdio : writeln;
    import std.datetime : Clock, Duration;
    import std.array : uninitializedArray;
    import std.random : uniform;

    alias result_type = long;
    alias value_type = int;
    alias vector_t = value_type[];
    alias index_type = typeof(vector_t.init.length);// Make index integrals portable - Linux is ulong, Win8.1 is uint

    immutable long N = 20000;
    immutable int size = 10;

    // Replaced for loops with appropriate foreach versions
    value_type scalar_product(in ref vector_t x, in ref vector_t y) { // "in" is the same as "const" here
      value_type res = 0;
      for(index_type i = 0; i < size; ++i)
        res += x[i] * y[i];
      return res;
    }

    int main() {
      auto tm_before = Clock.currTime;
      auto countElapsed(in string taskName) { // Factor out printing code
        writeln(taskName, ": ", Clock.currTime - tm_before);
        tm_before = Clock.currTime;
      }

      // 1. allocate and fill randomly many short vectors
      vector_t[] xs = uninitializedArray!(vector_t[])(N);// Avoid default inits of inner arrays
      foreach(ref x; xs)
        x = uninitializedArray!(vector_t)(size);// Avoid more default inits of values
      countElapsed("allocation");

      foreach(ref x; xs)
        foreach(ref val; x)
          val = uniform(-1000, 1000);
      countElapsed("random");

      // 2. compute all pairwise scalar products:
      result_type avg = 0;
      foreach(const ref x; xs)
        foreach(const ref y; xs)
          avg += scalar_product(x, y);
      avg /= N ^^ 2;// Replace manual multiplication with pow operator
      writeln("result: ", avg);
      countElapsed("scalar products");

      return 0;
    }

मैंने एलएलवीएम-आधारित संकलक का उपयोग करके इनमें से प्रत्येक परीक्षण को संकलित किया, क्योंकि एलडीसी प्रदर्शन के मामले में डी संकलन के लिए सबसे अच्छा विकल्प लगता है। मेरे x86_64 आर्क लिनक्स इंस्टॉलेशन पर मैंने निम्नलिखित पैकेजों का उपयोग किया:

  • clang 3.6.0-3
  • ldc 1:0.15.1-4
  • dtools 2.067.0-2

मैंने प्रत्येक को संकलित करने के लिए निम्नलिखित आदेशों का उपयोग किया:

  • सी ++: clang++ scalar.cpp -o"scalar.cpp.exe" -std=c++11 -O3
  • डी: rdmd --compiler=ldc2 -O3 -boundscheck=off <sourcefile>

परिणाम

स्रोत के प्रत्येक संस्करण के परिणाम ( कच्चे कंसोल आउटपुट का स्क्रीनशॉट ) निम्नानुसार है:

  1. scalar.cpp (मूल C ++):

    allocation: 2 ms
    
    random generation: 12 ms
    
    result: 29248300000
    
    time: 2582 ms

    सी ++ 2582 एमएस में मानक सेट करता है ।

  2. scalar.d (संशोधित ओपी स्रोत):

    allocation: 5 ms, 293 μs, and 5 hnsecs 
    
    random: 10 ms, 866 μs, and 4 hnsecs 
    
    result: 53237080000
    
    scalar products: 2 secs, 956 ms, 513 μs, and 7 hnsecs 

    यह ~ 2957 एमएस के लिए चला । C ++ कार्यान्वयन की तुलना में धीमा, लेकिन बहुत अधिक नहीं।

  3. scalar2.d (अनुक्रमणिका / लंबाई प्रकार परिवर्तन और अनइंस्टाललाइज़ किए गए अनुकूलन):

    allocation: 2 ms, 464 μs, and 2 hnsecs
    
    random: 5 ms, 792 μs, and 6 hnsecs
    
    result: 59
    
    scalar products: 1 sec, 859 ms, 942 μs, and 9 hnsecs

    दूसरे शब्दों में, ~ 1860 मि । अभी तक यह लीड में है।

  4. scalar3.d (Foreaches):

    allocation: 2 ms, 911 μs, and 3 hnsecs
    
    random: 7 ms, 567 μs, and 8 hnsecs
    
    result: 189
    
    scalar products: 2 secs, 182 ms, and 366 μs

    ~ 2182 एमएस की तुलना में धीमी हैscalar2.d , लेकिन सी ++ संस्करण की तुलना में तेज है।

निष्कर्ष

सही अनुकूलन के साथ, डी कार्यान्वयन वास्तव में उपलब्ध एलएलवीएम-आधारित संकलक का उपयोग करके अपने समकक्ष सी ++ कार्यान्वयन से अधिक तेजी से चला गया। अधिकांश अनुप्रयोगों के लिए डी और सी ++ के बीच का मौजूदा अंतर केवल वर्तमान कार्यान्वयन की सीमाओं के आधार पर लगता है।


8

dmd भाषा का संदर्भ कार्यान्वयन है और इस प्रकार अधिकांश कार्य बैकएंड को अनुकूलित करने के बजाए बग्स को ठीक करने के लिए सीमा में डाल दिया जाता है।

आपके मामले में "इन" तेज है क्योंकि आप डायनेमिक सरणियों का उपयोग कर रहे हैं जो संदर्भ प्रकार हैं। रेफ के साथ आप एक और स्तर का अप्रत्यक्ष परिचय देते हैं (जिसका उपयोग आम तौर पर सरणी को बदलने के लिए किया जाता है और केवल सामग्री नहीं)।

वैक्टर आमतौर पर उन स्ट्रक्चर्स के साथ लागू किए जाते हैं जहां कॉन्स्ट रिफ परफेक्ट हो जाता है। वेक्टर ऑपरेशन और यादृच्छिकता के भार की विशेषता वाली वास्तविक दुनिया उदाहरण के लिए smallptD बनाम smallpt देखें ।

ध्यान दें कि 64-बिट भी अंतर कर सकते हैं। मैंने एक बार याद किया कि x64 gcc पर 64-बिट कोड संकलित करता है जबकि dmd अभी भी 32 में डिफॉल्ट करता है (64-बिट कोडजेन परिपक्व होने पर बदल जाएगा)। "Dmd -m64 ..." के साथ एक उल्लेखनीय स्पीडअप था।


7

क्या C ++ या D तेज है, आप जो कर रहे हैं उस पर अत्यधिक निर्भर होने की संभावना है। मुझे लगता है कि जब अच्छी तरह से लिखित सी ++ की तुलना डी-लिखित कोड से की जाती है, तो वे आम तौर पर या तो समान गति के होंगे, या सी ++ तेज होंगे, लेकिन जो विशेष संकलक अनुकूलन करने का प्रबंधन करता है, वह भाषा से पूरी तरह से अलग हो सकता है। अपने आप।

हालांकि, वहाँ हैं कुछ मामलों में जहां विकास की गति के लिए C ++ की धड़कन का एक अच्छा मौका खड़ा है। मुख्य जो मन में आता है वह स्ट्रिंग प्रसंस्करण होगा। डी की सरणी को कम करने के लिए धन्यवाद कैपबल, स्ट्रिंग्स (और सामान्य रूप से सरणियों) को बहुत तेजी से संसाधित किया जा सकता है, जहां आप आसानी से सी ++ में कर सकते हैं। डी 1 के लिए, टैंगो का एक्सएमएल प्रोसेसर बेहद तेज है , मुख्य रूप से डी की सरणी स्लाइसिंग क्षमताओं के लिए धन्यवाद (और उम्मीद है कि डी 2 में एक समान तेजी से एक्सएमएल पार्सर होगा जो एक बार फोबोस के लिए काम किया जा रहा है)। तो, अंत में क्या डी या सी ++ तेजी से होने जा रहा है, जो आप कर रहे हैं उस पर बहुत निर्भर होने वाला है।

अब, मैं कर रहा हूँ आश्चर्य है कि आप इस विशेष मामले में गति में इस तरह के एक अंतर दिखाई देता है, लेकिन यह बात की तरह है कि मैं डीएमडी के रूप में बेहतर बनाता है सुधार करने के लिए उम्मीद करेंगे है। Gdc का उपयोग करने से बेहतर परिणाम मिल सकते हैं और संभवतः यह स्वयं की भाषा की तुलना (बैकएंड की तुलना में) होगी जो कि यह gcc- आधारित है। लेकिन यह मुझे बिल्कुल भी आश्चर्यचकित नहीं करेगा अगर कई चीजें हैं जो कोड को गति देने के लिए किया जा सकता है जो dmd उत्पन्न करता है। मुझे नहीं लगता कि इस बिंदु पर dmd की तुलना में gcc अधिक परिपक्व है कि बहुत अधिक सवाल है। और कोड अनुकूलन कोड परिपक्वता के प्रमुख फलों में से एक हैं।

अंततः, क्या मायने रखता है कि आपके विशेष एप्लिकेशन के लिए dmd कितना अच्छा प्रदर्शन करता है, लेकिन मैं इस बात से सहमत हूं कि यह जानना निश्चित रूप से अच्छा होगा कि C ++ और D सामान्य रूप से कितनी अच्छी तरह तुलना करते हैं। सिद्धांत रूप में, उन्हें बहुत अधिक समान होना चाहिए, लेकिन यह वास्तव में कार्यान्वयन पर निर्भर करता है। मुझे लगता है कि वास्तव में परीक्षण करने के लिए बेंचमार्क के एक व्यापक सेट की आवश्यकता होगी कि वर्तमान में दोनों की तुलना कितनी अच्छी है।


4
हाँ, मुझे आश्चर्य होगा कि इनपुट / आउटपुट या तो भाषा में काफी तेज था, या यदि शुद्ध गणित या तो भाषा में काफी तेज था, लेकिन स्ट्रिंग ऑपरेशन, मेमोरी मैनेजमेंट, और कुछ अन्य चीजें आसानी से एक भाषा को चमकने दे सकती हैं।
मैक्स लाइबर्ट

1
C ++ iostreams की तुलना में बेहतर (तेज) करना आसान है। लेकिन यह मुख्य रूप से एक पुस्तकालय कार्यान्वयन मुद्दा है (सबसे लोकप्रिय विक्रेताओं से सभी ज्ञात संस्करणों पर)।
बेन वोइगट

4

आप सी कोड लिख सकते हैं कि डी कितनी दूर है जो कि तेज है, यह बहुत सी चीजों पर निर्भर करेगा:

  • आप किस कंपाइलर का उपयोग करते हैं
  • आप किस सुविधा का उपयोग करते हैं
  • आप कैसे आक्रामक रूप से अनुकूलन करते हैं

पहले के अंतर को खींचना उचित नहीं है। दूसरा C ++ को इसका लाभ दे सकता है, क्योंकि यदि कुछ भी है, तो इसमें बहुत कम सुविधाएँ हैं। तीसरा एक मजेदार है: डी कोड को कुछ तरीकों से अनुकूलित करना आसान है क्योंकि सामान्य तौर पर इसे समझना आसान है। इसके अलावा इसमें क्रियात्मक और दोहरावदार लेकिन तेज़ कोड जैसी चीज़ों को छोटे रूपों में लिखने की अनुमति देने वाले बड़े पैमाने पर जेनेरिक प्रोग्रामिंग करने की क्षमता है।


3

कार्यान्वयन के मुद्दे की गुणवत्ता की तरह लगता है। उदाहरण के लिए, यहाँ मैं क्या परीक्षण कर रहा हूँ:

import std.datetime, std.stdio, std.random;

version = ManualInline;

immutable N = 20000;
immutable Size = 10;

alias int value_type;
alias long result_type;
alias value_type[] vector_type;

result_type scalar_product(in vector_type x, in vector_type y)
in
{
    assert(x.length == y.length);
}
body
{
    result_type result = 0;

    foreach(i; 0 .. x.length)
        result += x[i] * y[i];

    return result;
}

void main()
{   
    auto startTime = Clock.currTime();

    // 1. allocate vectors
    vector_type[] vectors = new vector_type[N];
    foreach(ref vec; vectors)
        vec = new value_type[Size];

    auto time = Clock.currTime() - startTime;
    writefln("allocation: %s ", time);
    startTime = Clock.currTime();

    // 2. randomize vectors
    foreach(ref vec; vectors)
        foreach(ref e; vec)
            e = uniform(-1000, 1000);

    time = Clock.currTime() - startTime;
    writefln("random: %s ", time);
    startTime = Clock.currTime();

    // 3. compute all pairwise scalar products
    result_type avg = 0;

    foreach(vecA; vectors)
        foreach(vecB; vectors)
        {
            version(ManualInline)
            {
                result_type result = 0;

                foreach(i; 0 .. vecA.length)
                    result += vecA[i] * vecB[i];

                avg += result;
            }
            else
            {
                avg += scalar_product(vecA, vecB);
            }
        }

    avg = avg / (N * N);

    time = Clock.currTime() - startTime;
    writefln("scalar products: %s ", time);
    writefln("result: %s", avg);
}

ManualInlineपरिभाषित के साथ मुझे 28 सेकंड मिलते हैं, लेकिन बिना मुझे 32 मिलते हैं। इसलिए कंपाइलर भी इस सरल कार्य को नहीं कर रहा है, जो मुझे लगता है कि यह स्पष्ट होना चाहिए।

(मेरी कमांड लाइन है dmd -O -noboundscheck -inline -release ...)


1
जब तक आप अपनी C ++ टाइमिंग की तुलना नहीं करते हैं, तब तक आपकी टाइमिंग बेकार है।
deceleratedcaviar

3
@ डैनियल: आप इस बिंदु को याद कर रहे हैं। यह अलगाव में डी अनुकूलन का प्रदर्शन करने के लिए था, अर्थात् निष्कर्ष के लिए मैंने कहा: "तो संकलक भी इस सरल फ़ंक्शन को सम्मिलित नहीं कर रहा है, जो मुझे लगता है कि यह स्पष्ट है कि यह होना चाहिए।" मैं इसे C ++ से तुलना करने का भी प्रयास कर रहा हूं, जैसा कि मैंने पहले वाक्य में स्पष्ट रूप से कहा था : "कार्यान्वयन मुद्दे की गुणवत्ता की तरह लगता है।"
GManNickG

आह सच, सॉरी :)। आप यह भी पाएंगे कि DMD कंपाइलर लूप्स को बिल्कुल भी वेक्टर नहीं करता है।
डेक्लेरेटेडकविर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.