2010-08-09 20 views
16

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

  • फ्लैश मेमोरी (हम एक अपेक्षाकृत सस्ती पीसीआई-एक्सप्रेस कार्ड के मालिक हैं, 1 TB की मेमोरी है कि पहुंचता है 1 जीबी/एस पढ़ा निरंतर प्रदर्शन)
  • एकाधिक कोर (हम एक सस्ते के मालिक हैं 16 हार्डवेयर धागे के साथ नेहलेम सर्वर)

सीएसवी पार्सर का पहला कार्यान्वयन एकल थ्रेड किया गया था। फाइल रीडिंग, कैरेक्टर डिकोडिंग, फ़ील्ड स्प्लिटिंग, टेक्स्ट पार्सिंग, सब एक ही धागे के भीतर। परिणाम लगभग 50 एमबी/एस का एक थ्रूपुट था। खराब नहीं है लेकिन भंडारण सीमा से नीचे ...

दूसरा कार्यान्वयन फ़ाइल को पढ़ने के लिए एक थ्रेड का उपयोग करता है (बाइट स्तर पर), एक धागा वर्णों को डीकोड करने के लिए (बाइटबफर से चारबफर तक), और कई धागे को पार्स करने के लिए खेतों (मेरा मतलब है कि सीमित पाठ फ़ील्ड को युगल, पूर्णांक, तिथियों में पार्स करना ...)। यह हमारे बॉक्स पर 400 एमबी/एस के करीब, तेजी से काम करता है।

लेकिन अभी भी हमारे संग्रहण के प्रदर्शन से काफी नीचे है। और भविष्य में उन एसएसडी में फिर से सुधार होगा, हम जावा में इसे अधिक से अधिक नहीं ले रहे हैं। यह स्पष्ट है कि वर्तमान सीमा वर्ण डिकोडिंग (CharsetDecoder.read (...)) है। यह एक बाधा है, एक शक्तिशाली नेहलेम प्रोसेसर पर यह बाइट्स को 400 एमबी/एस पर वर्णों में बदल देता है, बहुत अच्छा है, लेकिन इसे सिंगल थ्रेडेड होना चाहिए। CharsetDecoder कुछ हद तक राज्यव्यापी है, प्रयुक्त वर्णमाला के आधार पर, और multithreaded डिकोडिंग का समर्थन नहीं करता है।

तो समुदाय के लिए मेरा प्रश्न है (और अब तक पोस्ट पढ़ने के लिए धन्यवाद): क्या कोई जावा में वर्णसेट डिकोडिंग ऑपरेशन को समानांतर करने के बारे में जानता है?

उत्तर

2

क्या कोई जानता है कि जावा में वर्णसेट डिकोडिंग ऑपरेशन को समानांतर कैसे किया जाए?

आप ऐसा करने के लिए कई इनपुट स्ट्रीम खोलने में सक्षम हो सकते हैं (मुझे यकीन नहीं है कि आप एनआईओ के साथ इस बारे में कैसे जाएंगे, लेकिन यह संभव होना चाहिए)।

यह कितना मुश्किल होगा आप जिस एन्कोडिंग से डीकोड कर रहे हैं उस पर निर्भर करता है। लक्ष्य एन्कोडिंग के लिए आपको एक bespoke समाधान की आवश्यकता होगी। यदि एन्कोडिंग में निश्चित चौड़ाई है (उदा। विंडोज -1252), तो एक बाइट == एक वर्ण और डिकोडिंग आसान है।

आधुनिक चर-चौड़ाई एन्कोडिंग (जैसे यूटीएफ -8 और यूटीएफ -16) में चरित्र अनुक्रम के पहले बाइट की पहचान करने के लिए नियम होते हैं, इसलिए फ़ाइल के बीच में कूदना और डिकोडिंग शुरू करना संभव है (आप करेंगे पिछले खंड के अंत को ध्यान में रखना होगा, इसलिए फ़ाइल के अंत को डीकोड करना प्रारंभ करना बुद्धिमानी है)।

कुछ विरासत परिवर्तनीय-चौड़ाई एन्कोडिंग शायद यह अच्छी तरह डिज़ाइन नहीं हो सकती हैं, इसलिए आपके पास डेटा की शुरुआत से डीकोड करने के लिए कोई विकल्प नहीं होगा और इसे अनुक्रमिक रूप से पढ़ा जाएगा।

यदि यह एक विकल्प है, तो अपना डेटा यूटीएफ -16 बीई के रूप में उत्पन्न करें। फिर आप डीकोडिंग काट सकते हैं और दो बाइट सीधे एक char को पढ़ सकते हैं।

अगर फ़ाइल यूनिकोड है, तो बीओएम हैंडलिंग के लिए देखें, लेकिन मुझे लगता है कि आप निम्न स्तर के कई विवरणों से पहले ही परिचित हैं।

+0

दुर्भाग्यवश, यूटीएफ -16 एक परिवर्तनीय लंबाई एन्कोडिंग है। इस तरह के साधारण यूनिकोड पार्सिंग के लिए आपको यूटीएफ -32 की आवश्यकता है। – grddev

+0

@grddev - मैंने इसे अपनी पोस्ट में शामिल किया - यूटीएफ -16 डेटा धाराओं के मध्य में चरित्र अनुक्रमों की पहचान करना संभव है - उच्च सरोगेट जोड़े 0xD800-0xDBFF हैं और कम सरोगेट 0xDC00-0xDFFF हैं। बाइट्स की जोड़ी में कुछ और निहित है। – McDowell

+0

मेरी टिप्पणी यूटीएफ -16 बीई के उल्लेख को संदर्भित करती है। आप पूरी तरह से डीकोडिंग काट नहीं सकते हैं। लेकिन यह वास्तव में काफी सरल है। – grddev

1

यह स्पष्ट है कि वर्तमान सीमा वर्ण डिकोडिंग (CharsetDecoder.read (...))

आप कैसे जानते हैं? क्या आपकी निगरानी/प्रोफाइलिंग विशेष रूप से दिखाती है कि डिकोडर थ्रेड आपके कोर में से 100% का उपयोग कर रहा है?

एक और संभावना यह है कि ओएस एसएसडी को सैद्धांतिक अधिकतम गति पर चलाने में सक्षम नहीं है।

यदि यूटीएफ -8 डिकोडिंग निश्चित रूप से बाधा है तो कार्य को समानांतर में करना संभव होना चाहिए। लेकिन आपको यह करने के लिए निश्चित रूप से अपने स्वयं के डिकोडर्स को लागू करने की आवश्यकता होगी।

+0

हां, जेपीरोफाइलर का उपयोग करके कई रन स्पष्ट रूप से दिखाते हैं कि (एकल) वर्ण डिकोडिंग थ्रेड लगभग 100% सक्रिय है। मुझे प्रतिक्रियाओं में यूटीएफ -8 और यूटीएफ -16 एन्कोडिंग में कई संदर्भ दिखाई देते हैं। लेकिन हम यहां एक सामान्य उद्देश्य सीएसवी पार्सर लिख रहे हैं, जिसका उपयोग यूरोप, अमेरिका, जापान, चीन में हमारे ग्राहकों द्वारा मौजूदा फाइलों पर किया जाएगा ... इसलिए हम यह नहीं मान सकते कि कौन सी वर्णमाला का उपयोग किया जाएगा। विशेष रूप से हम यह नहीं मान सकते कि क्या वर्णमाला तय की जाएगी या नहीं। – Killerchamb

0

यदि आप एन्कोडिंग जानते हैं, और यह या तो निश्चित आकार है, या ओवरलैपिंग बाइट अनुक्रम नहीं है, तो आप एक विशेष अनुक्रम के लिए स्कैन कर सकते हैं। सीएसवी में, न्यूलाइन के लिए एक अनुक्रम समझ में आता है। यहां तक ​​कि यदि आप गतिशील रूप से एन्कोडिंग का पता लगाते हैं, तो आप एन्कोडिंग निर्धारित करने के लिए पहले कुछ बाइट्स का एक पास चला सकते हैं, और फिर समांतर डीकोडिंग पर आगे बढ़ सकते हैं।

+0

मुझे यह विचार बहुत पसंद है। सीधे कच्चे बाइट्स के भीतर delimitters का पता लगाने। और हां, NEW_LINE पैटर्न एक CSV पार्सर के लिए सही उम्मीदवार है। लेकिन मुझे किसी भी वर्णमाला का समर्थन करना है।क्या आप वर्णमाला कार्यान्वयन के आसपास कुछ सामान्य विधि से अवगत हैं जो बताता है कि बाइट पैटर्न ओवरलैप हैं या नहीं? मैं जावाडोक में कोई नहीं देखता हूं। – Killerchamb

+0

@ एंटोनी: दुर्भाग्य से, मुझे कोई जानकारी नहीं है। यह किसी भी यूटीएफ-एन्कोडिंग, या सामान्य रूप से किसी निश्चित-चौड़ाई एन्कोडिंग में कोई समस्या नहीं होनी चाहिए। [इस सवाल के अनुसार] (http://stackoverflow.com/questions/724247/newline-control-characters-in-multi-byte-character-sets) सामान्य जापानी एन्कोडिंग के लिए भी कोई समस्या नहीं होनी चाहिए। चाहे चीनी (या अन्य) एन्कोडिंग में कोई भी न्यूलाइन प्रस्तुतिकरण ओवरलैप हो, मुझे नहीं पता। यह किसी भी मामले में स्पष्ट है कि जावा में मौजूदा इंटरफेस इस अच्छी तरह से करने के साधन प्रदान नहीं करता है। :( – grddev

0

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

यदि दूसरा खंड गलत हो जाता है, तो आपको इसे फिर से करना होगा, इसलिए समानांतर में बड़े हिस्से को नहीं करना महत्वपूर्ण है। यदि आप समानांतर में दो से अधिक हिस्सों को करते हैं, तो शुरुआत से अंत तक 'मरम्मत' करना महत्वपूर्ण होगा, ताकि एक गलत गलती ब्लॉक न हो, जिसके परिणामस्वरूप अगले ब्लॉक को अमान्य कर दिया जा सके (जिसे सही ढंग से गठबंधन किया जा सकता है)।

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