2011-09-07 12 views
5

तो मेरे पास यह जावा प्रोग्राम है जिसका उपयोग मैं डेटा के कई टेराबाइट्स के माध्यम से करने के लिए करता हूं। प्रदर्शन एक चिंता है।जावा में कुशल स्ट्रोड?

मैं एप्लिकेशन प्रोफाइल है, और सभी स्मृति आवंटन के एक बड़े अंश के साथ ही CPU समय के एक बड़े अंश एक साधारण कार्य को करते से आते हैं:

मैं ASCII वर्ण की एक सरणी है। मुझे पता है कि ऑफसेट i के ऑफसेट j ऑफसेट करने के लिए एक फ़्लोटिंग-पॉइंट नंबर का प्रतिनिधित्व करते हैं। मुझे उस फ़्लोटिंग-पॉइंट नंबर को double में निकालने की आवश्यकता है।

बेवकूफ Double.parseDouble(new String(buf, i, j - i)) नौकरी करता है। हालांकि, इस जहां में बहुत समय खर्च किया जाता है और स्मृति आवंटन का एक बहुत से आते हैं, शायद इसलिए कि:

  • new String() एक नई वस्तु बनाता है, बनाता है एक आंतरिक char[] सरणी और प्रतियां सरणी में पात्रों;
  • Double.parseDouble() एक FloatingDecimal वस्तु बनाता है, और भी एक char[] सरणी, भी इसे में पात्रों को कॉपी बनाता है।

ये सभी आवंटन और यह सभी प्रतिलिपि वास्तव में आवश्यक नहीं हैं। क्या मैं उनसे बच सकता हूं?

मैं वास्तव में क्या चाहते चाहते एक strtod की तरह समारोह है कि एक char[] (या एक byte[]) के साथ ही प्रारंभ/समाप्ति ऑफसेट ले जाएगा, और एक double वापसी है।

कोई सुझाव? क्या मुझे अपना खुद का रोल करना चाहिए? क्या मुझे strtod के आसपास जेएनआई रैपर लिखना चाहिए? क्या मुझे कुछ जावा लाइब्रेरी का उपयोग करना चाहिए जो पहले से ही बाहर है?

+0

वास्तव में, String.substring विधि नकल नहीं करता है प्रारंभिक सरणी स्ट्रिंग कन्स्ट्रक्टर एक बाधा है तो यह उपयोगी हो सकता है। –

उत्तर

5

मैंने पहले जो किया है वह बाइटबफर (बाइट से चार एन्कोडिंग रूपांतरण से बचने के लिए) को डबल और वीजा-विपरीत के लिए एक पार्सर लिखता है। यदि आप किसी भी वस्तु को बनाने से बच सकते हैं तो यह बहुत तेज़ हो सकता है। यह दृष्टिकोण स्मृति प्रतिलिपि फ़ाइलों के लिए भी काम करता है जो कुछ कॉपी लागतों से परहेज करते हैं।

कोर कोड निम्न जैसा दिखता है। यह घाटे को संभाल नहीं करता है, लेकिन आप इसे जोड़ सकते हैं।

@Override 
public double read() throws BufferUnderflowException { 
    long value = 0; 
    int exp = 0; 
    boolean negative = false; 
    int decimalPlaces = Integer.MIN_VALUE; 
    while (true) { 
    byte ch = buffer.get(); 
    if (ch >= '0' && ch <= '9') { 
     while (value >= MAX_VALUE_DIVIDE_10) { 
     value >>>= 1; 
     exp++; 
     } 
     value = value * 10 + (ch - '0'); 
     decimalPlaces++; 
    } else if (ch == '-') { 
     negative = true; 
    } else if (ch == '.') { 
     decimalPlaces = 0; 
    } else { 
     break; 
    } 
    } 

    return asDouble(value, exp, negative, decimalPlaces); 
} 

The full code

यह जैसे ही यह किसी भी बाइट यह उदा उम्मीद नहीं है हो जाता है बंद हो जाता है एक , या \n

+0

(+1) अच्छा, साझा करने के लिए धन्यवाद! – NPE

+0

बाइटबफर के रूप में डबल को एन्कोड करने के लिए कोड भी है। –

5

मैं java.lang.Double के लिए स्रोत पर देखने चाहते हैं, मेरे अपने सहायक वर्ग के लिए कोड है कि parseDouble करता है बाहर कॉपी और offset और length सीधे साथ char[] पर काम करने की इसे संशोधित।

+0

यह एक विकल्प है, सिवाय इसके कि यह मूल रूप से 'फ़्लोटिंग डेसीमल' करता है और यह लगभग ~ 3K लाइनों की कोड है जिसमें पूरे स्मृति बिखरे हुए मेमोरी आवंटन होते हैं। वास्तव में हैकिंग की कल्पना न करें कि अगर मैं इसकी मदद कर सकता हूं (जेएनआई मार्ग बहुत अधिक आकर्षक लगता है)। – NPE

1

यदि आप एक कुशल सी कार्यान्वयन जानते हैं, तो आप जेएनआई के साथ इसके लिए एक रैपर लिख सकते हैं।

+0

हालांकि आप जेएनआई ओवरहेड जोड़ रहे होंगे (मुझे लगता है कि इसमें कुछ लागत है)। – Thilo

+0

यदि यह एक स्थिर कार्य है, तो ओवरहेड शायद काफी उचित है। इसका पता लगाने का एकमात्र तरीका यह है कि इसे आजमाएं! –

2

जिज्ञासा से मैं जावा में strtod समारोह की नकल की और ~ 10 समय speedup Double.parseDouble (स्ट्रिंग) विधि की तुलना में मिल गया (यहां तक ​​कि पाश में नए तार बनाने के बिना)। लेकिन शायद यह आपके कार्यान्वयन के लिए पर्याप्त नहीं है।

माइक्रो बेंच मार्किंग देता है:

Double.parseDouble(): 1.6M रूपांतरण/दूसरा
जावा strtod() विधि: 10.5M रूपांतरण/दूसरा

+0

(+1) बहुत बढ़िया, ऐसा करने के लिए धन्यवाद। ब्याज से, जो आपने 'स्ट्रेटोड' कार्यान्वयन किया था? इस लिंक से – NPE

+1

: [http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/missing/strtod.c](http://svn.ruby-lang.org/repos/ruby/branches /ruby_1_8/missing/strtod.c) – styken

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