JSON.Unmarshal बनाम json.NewDecoder.Decode का उपयोग करके JSON को डिकोड करना


202

मैं एक API क्लाइंट विकसित कर रहा हूँ जहाँ मुझे अनुरोध पर JSON पेलोड को एनकोड करना होगा और प्रतिक्रिया से JSON बॉडी को डीकोड करना होगा।

मैंने कई पुस्तकालयों से स्रोत कोड पढ़ा है और जो मैंने देखा है, उसमें मूल रूप से JSON स्ट्रिंग को एन्कोडिंग और डिकोड करने की दो संभावनाएँ हैं।

json.Unmarshalसंपूर्ण प्रतिक्रिया स्ट्रिंग पास करने का उपयोग करें

data, err := ioutil.ReadAll(resp.Body)
if err == nil && data != nil {
    err = json.Unmarshal(data, value)
}

या उपयोग कर रहा है json.NewDecoder.Decode

err = json.NewDecoder(resp.Body).Decode(value)

मेरे मामले में, जब लागू होने वाली HTTP प्रतिक्रियाओं से निपटने के लिए io.Reader, दूसरे संस्करण को कम कोड की आवश्यकता होती है, लेकिन जब से मैंने दोनों को देखा है तो मुझे आश्चर्य होता है कि क्या कोई वरीयता है कि क्या मुझे दूसरे के बजाय एक समाधान का उपयोग करना चाहिए।

इसके अलावा, इस प्रश्न से स्वीकृत उत्तर कहता है

के json.Decoderबजाय का उपयोग करें json.Unmarshal

लेकिन इसका कारण नहीं बताया। क्या मुझे वास्तव में उपयोग करने से बचना चाहिए json.Unmarshal?


GitHub पर इस पुल अनुरोध ने json.NewDecoder के साथ अनमरशाल को "JSON डिकोडिंग में बफर हटाने के लिए" कॉल को बदल दिया।
मैट

यह सिर्फ इस बात पर निर्भर करता है कि आपके लिए कौन सा इनपुट अधिक सुविधाजनक है। blog.golang.org/json-and-go दोनों तकनीकों का उपयोग करने के उदाहरण देता है।
रेक्सपोसैडस

15
IMO, ioutil.ReadAllहै लगभग हमेशा के लिए गलत बात। यह आपके लक्ष्य से संबंधित नहीं है, लेकिन आपको पाइप के नीचे जो भी आ रहा है उसे स्टोर करने के लिए पर्याप्त सन्निहित मेमोरी की आवश्यकता होती है, भले ही प्रतिक्रिया का अंतिम 20TB }आपके JSON में अंतिम के बाद हो ।
डस्टिन

@ डस्टिन आप इसे io.LimitReaderरोकने के लिए उपयोग कर सकते हैं ।
इनक गमुस

जवाबों:


240

यह वास्तव में इस बात पर निर्भर करता है कि आपका इनपुट क्या है। यदि आप की Decodeविधि के कार्यान्वयन को देखते हैं json.Decoder, तो यह एक गो मूल्य में अनमर्सहॉलिंग करने से पहले मेमोरी में संपूर्ण JSON मान को बफ़र करता है। इसलिए ज्यादातर मामलों में यह अधिक मेमोरी कुशल नहीं होगा (हालाँकि यह भाषा के भविष्य के संस्करण में आसानी से बदल सकता है)।

अतः अंगूठे का एक बेहतर नियम यह है:

  • json.Decoderयदि आपका डेटा किसी io.Readerस्ट्रीम से आ रहा है, तो उपयोग करें या आपको डेटा की एक स्ट्रीम से कई मानों को डीकोड करने की आवश्यकता है।
  • json.Unmarshalयदि आपके पास पहले से JSON डेटा स्मृति में है तो उसका उपयोग करें ।

HTTP अनुरोध से पढ़ने के मामले के लिए, मैं json.Decoderतब से चुनूंगा जब आप स्पष्ट रूप से एक स्ट्रीम से पढ़ रहे हों।


25
इसके अलावा: गो 1.3 स्रोत कोड का निरीक्षण करके, हम यह भी सीख सकते हैं कि एन्कोडिंग के लिए, यदि आप एक json.Encoder का उपयोग करते हैं, तो यह एक वैश्विक बफर पूल (नए सिंक द्वारा समर्थित) का पुन: उपयोग करेगा, जिसे बफर मंथन में कमी करनी चाहिए यदि आप बहुत सारे जुबान को कूट रहे हैं। वहाँ केवल एक वैश्विक पूल है इसलिए विभिन्न json.Encoder का हिस्सा है। इसका कारण json.Marshal इंटरफ़ेस के लिए नहीं किया जा सकता है क्योंकि बाइट उपयोगकर्ता को वापस कर दिए जाते हैं और उपयोगकर्ता के पास बाइट्स को पूल में "वापस" करने का कोई तरीका नहीं होता है। तो अगर आप बहुत सारे एन्कोडिंग कर रहे हैं, तो json.Marshal में हमेशा थोड़ा सा बफर मंथन होता है।
अक्ताउ

@ फैली: क्या आपको यकीन है? स्रोत कोड अभी भी कहता है कि यह डिकोडिंग से पहले बफर में पूरे मूल्य को पढ़ता है: github.com/golang/go/blob/master/src/encoding/json/…Bufferedविधि आप किसी अतिरिक्त डेटा है कि मूल्य के बाद आंतरिक बफर में पढ़ा गया था देखने देने के लिए नहीं है।
जेम्स हेनस्ट्रिज

@JamesHenstridge: नहीं, आप शायद सही हैं। मैं सिर्फ आपके कथन की व्याख्या आपके इरादे से अलग कर रहा था। भ्रम के लिए क्षमा याचना।
फ्लिम्ज़ि
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.