2012-04-12 8 views
5

में लक्ष्य this C++ example में के रूप में ही प्रभाव को प्राप्त करने के लिए है: temporaries बनाने से बचें। मैंने सफलता के बिना सी ++ उदाहरण डी को अनुवाद करने का प्रयास किया है। मैंने विभिन्न दृष्टिकोणों का भी प्रयास किया है।अभिव्यक्ति टेम्पलेट्स डी

import std.datetime : benchmark; 
import std.stdio : writefln, writeln; 

void bench(alias fun, string time = "msecs")(string msg, uint n = 1_000_000) { 
    auto b = benchmark!fun(n); 
    writefln(" %s: %s ms", msg, b[0].to!(time, int)); 
} 

alias double Real; 

struct Expression(string op, E1, E2) { 
    E1 _v1; 
    E2 _v2; 
    alias _v1 v1; 
    alias _v2 v2; 

    auto opIndex(size_t i) { 
    return mixin("v1[i]" ~ op ~ "v2[i]"); 
    } 

    auto opBinary(string op, E)(auto ref E e) { 
    return Expression!(op, typeof(this), E)(this, e); 
    } 
} 

struct ExpVector { 

    Real[40] _data = void; 
    alias _data this; 

    this(Real datum) pure nothrow { _data = datum; } 

    auto opBinary(string op, T)(auto ref T other) { 
    return Expression!(op, typeof(this), T)(this, other); 
    } 

    void opAssign(E)(auto ref E exp) { 
    foreach(i, ref datum; _data) 
     datum = exp[i]; 
    } 
} 

struct Vector { 

    Real[40] _data = void; 
    alias _data this; 

    this(Real datum) pure nothrow { _data = datum; } 

    auto opBinary(string op)(auto ref Vector other) { 
    Vector ret; 
    foreach(i, datum; _data) 
     ret[i] = mixin("datum" ~ op ~ "other[i]"); 
    return ret; 
    } 
} 

void main() { 

    ExpVector e1 = ExpVector(1.5); 
    ExpVector e2 = ExpVector(7.3); 
    ExpVector ef; 
    void T1() { 
    ef = (e1 + e2) * (e1 + e2); 
    } 
    bench!T1(" vector operations using template expression"); 

    Vector v1 = Vector(1.5); 
    Vector v2 = Vector(7.3); 
    Vector vf; 
    void T2() { 
    vf = (v1 + v2) * (v1 + v2); 
    } 
    bench!T2(" regular vector operations"); 

    void T3() { 
    for(int i = 0; i < vf.length; ++i) 
     vf[i] = (v1[i] + v2[i]) * (v1[i] + v2[i]); 
    } 
    bench!T3(" what is expected if template expressions worked and temporaries were not created."); 
} 

अभिव्यक्ति टेम्पलेट संस्करण गैर अभिव्यक्ति टेम्पलेट संस्करण की तुलना में धीमी है। मैं अभिव्यक्ति टेम्पलेट संस्करण को अपेक्षाकृत तेज़ी से और अपेक्षित होने के करीब होने की उम्मीद कर रहा था। तो मेरे अभिव्यक्ति टेम्पलेट्स में क्या गलत है? डी में अभिव्यक्ति टेम्पलेट करने का सही तरीका क्या है?

+1

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

+0

मुझे लगता है कि आपने जो कहा है उसे गलत समझा है। मेरे द्वारा पोस्ट किया गया कोड अभिव्यक्ति टेम्पलेट के बिना संस्करण जितना धीमा है, यानी, केवल एक नियमित 'वेक्टर' संरचना है जो डीएमडी के साथ संकलित दोनों संस्करणों के साथ 'ओपिनरी' सदस्य फ़ंक्शन लागू करती है। मैं इसे विकिपीडिया में सी ++ कोड से तुलना नहीं कर रहा हूं। – Arlen

+0

फिर आपको दोनों संस्करणों को पोस्ट करना चाहिए। किसी चीज की तुलना किसी और चीज की तुलना करना मुश्किल है जब आपके पास केवल दो में से एक है। –

उत्तर

2

विकिपीडिया के C++ उदाहरण अभिव्यक्ति कक्षाओं में temporaries के लिए संदर्भ रखती है, और अभिव्यक्ति के मामले में ...

 
Vec a, b; 
double c; 
Vec result = (a - b) * c 
... ठीक पहले काम वेक्टर परिणाम के लिए हम स्मृति में पेड़ के कुछ प्रकार है:
a   b 
\  /
    \ /
    \ /
VecDifference 
     \ 
     \ 
     \ 
     VecScaled(has copy of 'c' embedded directly in object) 
VecDifference hold just references to a and b, and VecScaled holds reference to temporary VecDifference (which, according to the c++ rules, will be alive until expression end). At the end we have no duplication of initial data and no unnecessary computations(if we will use just some components of vector, but not all of them as in simple assignment to Vec)
In your struct Expression(string op, E1, E2) initial and intermediate data simply copied to data members and at the end of previous expression you will have
 
Expression!("*", Expression!("-", Vec, Vec), double) 
जहां बाहरी अभिव्यक्ति भीतरी अभिव्यक्ति की कॉपी करना होगा ("-", ग्राम शिक्षा समिति, वी.ई.सी) और डबल मापदंडों और भीतरी अभिव्यक्ति प्रतियां ए और बी वैक्टर की होगा। तो एक दिन के अंत में आपने अस्थायी वेक से परहेज किया लेकिन ए और बी की 4 प्रतियां (परिणाम वेक्टर को अंतिम असाइनमेंट की गणना नहीं) की। हालांकि, यह नहीं पता कि डी में इस स्थिति में प्रतिलिपि से कितनी अच्छी तरह से बचें। शायद संरचनाओं के लिए पॉइंटर्स?
(btw, ग temporaries को संदर्भ के साथ ++ 11 ऑटो प्रकार निष्कर्ष और अभिव्यक्ति टेम्पलेट्स दुर्भाग्यपूर्ण बातचीत, जो कीड़े को जन्म दे सकता है: http://lanzkron.wordpress.com/2011/02/21/inferring-too-much/)

+0

मुझे प्रतिलिपि के बारे में पता था, लेकिन डी मुझे संदर्भ के रूप में नहीं जाने देगा। मैंने पॉइंटर का प्रयास किया (मैं उस छाप के नीचे था जो मेरा कोड असुरक्षित कर देगा) और इससे बड़ा अंतर आता है, लेकिन अभी भी काफी कुछ नहीं है। उदाहरण के लिए, अभिव्यक्ति टेम्पलेट संस्करण '250ms' लेता है जबकि' 150ms' की अपेक्षा की जाती है। – Arlen

+0

हां, पॉइंटर्स चीजों को असुरक्षित बनाता है। मेरे उत्तर के अंत में लिंक किया गया पृष्ठ इस तरह के खतरों में से एक दिखाता है (यह सी ++ के बारे में है, लेकिन मुझे लगता है कि हम पॉइंटर्स के साथ डी में अभिव्यक्ति टेम्पलेट का उपयोग करके एक ही परिणाम प्राप्त कर सकते हैं) – cybevnm

संबंधित मुद्दे