2011-08-26 19 views
6

में बाइट्स पढ़ने का सबसे तेज तरीका है मैं एक डी 2 आवेदन में एक फ़ाइल से यथासंभव शीघ्र ही बाइट्स पढ़ना चाहते हैं। एप्लिकेशन को बाइट प्रति बाइट की आवश्यकता है, इसलिए डेटा के बड़े ब्लॉक पढ़ने से पाठक को इंटरफ़ेस का विकल्प नहीं है। https://github.com/gizmomogwai/performance:डी 2

इसके लिए मैं कम से सी ++, जावा, डी 2 में कुछ तुच्छ कार्यान्वयन बनाया।

आप देख सकते हैं मैंने कोशिश की सादा पढ़ता है, आवेदन कोड और स्मृति में बफर मैप की फ़ाइलें। मेरे उपयोग के लिए मेमोरी मैप किए गए समाधान ने सबसे अच्छा काम किया, लेकिन अजीब चीज यह है कि डी 2 जावा से धीमी है। मैं उम्मीद करता था कि सी 2+ और जावा के बीच डी 2 की भूमि होगी (सी ++ कोड -ओ 3-जी के साथ संकलित किया गया है, डी 2 कोड -ओ-रिलीज के साथ संकलित है)।

तो कृपया मुझे बताओ मैं गलत यहाँ क्या कर रहा हूँ और कैसे डी 2 कार्यान्वयन में तेजी लाने के।

class StdioFileReader { 
private: 
    FILE* fFile; 
    static const size_t BUFFER_SIZE = 1024; 
    unsigned char fBuffer[BUFFER_SIZE]; 
    unsigned char* fBufferPtr; 
    unsigned char* fBufferEnd; 

public: 
    StdioFileReader(std::string s) : fFile(fopen(s.c_str(), "rb")), fBufferPtr(fBuffer), fBufferEnd(fBuffer) { 
    assert(fFile); 
    } 
    ~StdioFileReader() { 
    fclose(fFile); 
    } 

    int read() { 
    bool finished = fBufferPtr == fBufferEnd; 
    if (finished) { 
     finished = fillBuffer(); 
     if (finished) { 
    return -1; 
     } 
    } 
    return *fBufferPtr++; 
    } 

private: 
    bool fillBuffer() { 
    size_t l = fread(fBuffer, 1, BUFFER_SIZE, fFile); 
    fBufferPtr = fBuffer; 
    fBufferEnd = fBufferPtr+l; 
    return l == 0; 
    } 
}; 

size_t readBytes() { 
    size_t res = 0; 
    for (int i=0; i<10; i++) { 
    StdioFileReader r("/tmp/shop_with_ids.pb"); 
    int read = r.read(); 
    while (read != -1) { 
     ++res; 
     read = r.read(); 
    } 
    } 
    return res; 
} 

जो बहुत तेजी से विकास में "एक ही" समाधान की तुलना में है:

struct FileReader { 

    private FILE* fFile; 
    private static const BUFFER_SIZE = 8192; 
    private ubyte fBuffer[BUFFER_SIZE]; 
    private ubyte* fBufferPtr; 
    private ubyte* fBufferEnd; 

    public this(string fn) { 
    fFile = std.c.stdio.fopen("/tmp/shop_with_ids.pb", "rb"); 
    fBufferPtr = fBuffer.ptr; 
    fBufferEnd = fBuffer.ptr; 
    } 
    public int read(ubyte* targetBuffer) { 
    auto finished = fBufferPtr == fBufferEnd; 
    if (finished) { 
     finished = fillBuffer(); 
     if (finished) { 
     return 0; 
     } 
    } 
    *targetBuffer = *fBufferPtr++; 
    return 1; 
    } 
    private bool fillBuffer() { 
    fBufferPtr = fBuffer.ptr; 
    auto l = std.c.stdio.fread(fBufferPtr, 1, BUFFER_SIZE, fFile); 
    fBufferEnd = fBufferPtr + l; 
    return l == 0; 
    } 
} 

size_t readBytes() { 
    size_t count = 0; 
    for (int i=0; i<10; i++) { 
    auto reader = FileReader("/tmp/shop_with_ids.pb"); 
    ubyte buffer[1]; 
    ubyte* p = buffer.ptr; 
    auto c = reader.read(p); 
    while (1 == c) { 
     ++count; 
     c = reader.read(p); 
    } 
    } 
    return count; 
} 
+1

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

+1

हाँ ... आप सही हैं ... मैं उम्मीद नहीं करता कि जावा सीपीपी से बहुत धीमी हो (जो अभी भी मेरे डेमो उदाहरण में डिफ़ॉल्ट जिट का उपयोग कर रहा है), लेकिन मेरा मुद्दा यह है कि डी भी धीमा है। मुझे उम्मीद थी कि डी सीपी के बराबर होगा। – Gizmomogwai

+0

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

उत्तर

3

यह बहुत संभावना है

आप उपयोग के मामले यहां की एक विचार एक सी ++ कार्यान्वयन है देने के लिए sfread की वजह से। कोई भी डी में समान रूप से ऐसा करने की गारंटी नहीं देता है - सी में आप एक अलग सीआरटी का उपयोग कर रहे हैं (जब तक आप डिजिटल मंगल सी ++ कंपाइलर का उपयोग नहीं कर रहे हैं?)।

इसका मतलब है कि पुस्तकालय तुल्यकालन तरह बातें, आदि कर किया जा सकता है जो धीमी गति से चीजों को नीचे। एकमात्र तरीका जिसे आप जान सकते हैं बल डी समान लाइब्रेरी से लिंक करने के लिए लिंकर को बताकर सी के समान लाइब्रेरी का उपयोग करने के लिए है।

जब तक आप ऐसा कर सकते हैं, तो आप संतरे के लिए सेब की तुलना कर रहे। यदि यह संभव नहीं है, तो ओएस को सीधे दोनों, और पर परिणामों की तुलना करें - इस तरह आप गारंटी देते हैं कि अंतर्निहित कॉल दोनों के लिए समान है।

+0

आप बिल्कुल सही हैं। मुझे नहीं पता कि फ्रेड के कार्यान्वयन समान हैं या नहीं। लेकिन मेरा सवाल यह है कि जावा में या सी ++ में जितनी तेजी से डी 2 में कार्यक्षमता को कार्यान्वित करना है। – Gizmomogwai

+0

@Gizmomogwai: ठीक है, लेकिन इस सवाल का निहितार्थ यह है कि डी स्वाभाविक रूप से धीमा है। ऐसी भाषा के बीच एक बड़ा अंतर है जो स्वाभाविक रूप से धीमा है क्योंकि इसके डिज़ाइन को मूल रूप से बहुत अधिक ओवरहेड और ऐसी भाषा की आवश्यकता होती है जहां एक छोटा क्षेत्र धीमा हो क्योंकि यह अभी तक अनुकूल नहीं है। – dsimcha

+0

@Gizmomogwai: इसे जावा में या सी ++ के रूप में तेज़ी से कार्यान्वित करने के लिए, आपको बस जो कुछ भी कर रहे हैं उसे करना है - जिसका शायद मतलब है कि आपको मूल ओएस कॉल ('रीडफाइल'' पर अपना स्वयं का buffered wrapper बनाना चाहिए विंडोज़) और इसका इस्तेमाल करें, फिर देखें कि यह कैसा चल रहा है। यह आपको बताएगा कि यह एक भाषा समस्या है या पुस्तकालय की समस्या है। – Mehrdad

1

क्या हुआ अगर आप std.stdio module का उपयोग होता है:

import std.stdio; 

struct FileReader { 

    private File fFile; 
    private enum BUFFER_SIZE = 8192;//why not enum? 
    private ubyte[BUFFER_SIZE] fBuffer=void;//avoid (costly) initialization to 0 
    private ubyte[] buff; 

    public this(string fn) { 
    fFile = File("/tmp/shop_with_ids.pb", "rb"); 
    } 

    /+ 
    public ~this(){//you really should have been doing this if you used std.c.stdio.fopen 
       //but it's unnecessary for std.stdio's File (it's ref counted) 
    fFile.close(); 
    } 
    +/ 

    public int read(out ubyte targetBuffer) { 
    auto finished = buff.length==0; 
    if (finished) { 
     finished = fillBuffer(); 
     if (finished) { 
     return 0; 
     } 
    } 
    targetBuffer = buff[0]; 
    buff = buff[1..$]; 
    return 1; 
    } 
    private bool fillBuffer() { 
    if(!fFile.isOpen())return false; 

    buff = fFile.rawRead(fBuffer[]); 

    return buff.length>0; 
    } 
} 

size_t readBytes() { 
    size_t count = 0; 
    for (int i=0; i<10; i++) { 
    auto reader = FileReader("/tmp/shop_with_ids.pb"); 
    ubyte buffer; 
    auto c = reader.read(buffer); 
    while (1 == c) { 
     ++count; 
     c = reader.read(buffer); 
    } 
    } 
    return count; 
} 

अगर आप सही गति तुलना आप के साथ -release -O -inline संकलन चाहिए (इस बंद हो जाती है डिबगिंग (ज्यादातर सरणी OOB चेक) चाहते का अनुकूलन और inlines क्या यह कर सकता है) (और निश्चित रूप से सी ++ समाधान के समान)

+0

आपकी टिप्पणियों के लिए धन्यवाद। असल में मैंने डी 2 कोड को -O -release के साथ संकलित किया (-इनलाइन मेरे सभी उदाहरणों के लिए धीमी थी)। मैं अपने कार्यक्रम (fillBuffer buff.length == 0 लौटना चाहिए) को सही और मेरे बेंचमार्क (80ms है जो सीपीपी-mmapped समाधान की तुलना में) मेरी मशीन पर 600 मि.से सामने आए। github पेज पर टेबल देखें। – Gizmomogwai