json.Unmarshal बनाम NewDecoder.Decode: Go में कौन सा तेज़ है?

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

दो कलाबाज़ भाई: Unmarshal और Decode

\n\n

यदि आप Go में लिखते हैं और JSON के साथ काम करते हैं, तो देर-सबेर आपके सामने यह विकल्प आता है: json.Unmarshal का उपयोग करें या json.NewDecoder.Decode का? यह प्रश्न इतना लोकप्रिय है कि Stack Overflow पर इसने हज़ारों बार देखा गया है और दर्जनों वोट प्राप्त किए हैं। लेकिन वहाँ आपको जो उत्तर मिलेगा, वह अक्सर "यह कार्य पर निर्भर करता है" तक सीमित होता है।

\n\n

आज हम केवल एक सारगर्भित उत्तर नहीं देंगे। हम अपनी स्वयं की जाँच करेंगे: दोनों विधियों की आंतरिक कार्यप्रणाली को समझेंगे, बेंचमार्क लिखेंगे, वास्तविक कोड उदाहरण दिखाएंगे, और स्पष्ट नियम बनाएंगे कि कब क्या उपयोग करना चाहिए। तैयार हो जाइए — यह गरमागरम होने वाला है!

\n\n

मुख्य बात संक्षेप में: Unmarshal और Decode क्या हैं?

\n\n

दोनों उपकरण एक ही काम करते हैं — JSON को Go संरचना में बदलना। लेकिन वे इसे अलग-अलग तरीके से करते हैं।

\n\n
    \n
  • json.Unmarshal — इनपुट के रूप में []byte और एक संरचना का पॉइंटर लेता है। सब कुछ एक साथ: बाइट्स मौजूद हैं, संरचना तैयार है, चलिए शुरू करते हैं। यह "सीधा" काम करता है — मेमोरी में डेटा के पूरे ऐरे को डिसीरियलाइज़ करता है।
  • \n
  • json.NewDecoder.Decode — स्ट्रीम (io.Reader) के साथ काम करता है। आप एक डिकोडर बनाते हैं, उसे एक रीडर (जैसे, os.File या http.Response.Body) देते हैं और Decode को कॉल करते हैं। डिकोडर डेटा को भागों में पढ़ता है, बिना सब कुछ एक साथ मेमोरी में लोड किए।
  • \n
\n\n

स्पष्ट रूप से, अंतर स्पष्ट है: बड़े डेटा के लिए — Decoder, छोटे के लिए — Unmarshal। लेकिन शैतान, हमेशा की तरह, विवरण में है।

\n\n

आंतरिक कार्यप्रणाली: वे हुड के नीचे कैसे काम करते हैं

\n\n

json.Unmarshal — स्नाइपर शॉट

\n\n

Unmarshal एक फ़ंक्शन है जो:

\n
    \n
  1. बाइट्स का एक स्लाइस लेता है।
  2. \n
  3. परिणामी संरचना के लिए मेमोरी आवंटित करता है।
  4. \n
  5. एक बार में पूरे JSON को पार्स करता है और संरचना को भरता है।
  6. \n
\n\n

सब कुछ सरल और सुरुचिपूर्ण है। लेकिन एक बारीक बात है: यदि आप Unmarshal में एक बड़ा JSON (जैसे, 100 MB) पास करते हैं, तो पहले आपको उन 100 MB को मेमोरी में पढ़ना होगा। और फिर Unmarshal संरचना के लिए और मेमोरी आवंटित करेगा। परिणाम — RAM की दोगुनी खपत।

\n\n

json.NewDecoder.Decode — प्लंबर

\n\n

Decoder अलग तरह से काम करता है:

\n
    \n
  1. एक नया डिकोडर बनाया जाता है, जो io.Reader को लपेटता है।
  2. \n
  3. डिकोडर डेटा को बफ़र में पढ़ता है (डिफ़ॉल्ट रूप से 4 KB)।
  4. \n
  5. पढ़ने के साथ-साथ, यह JSON को टोकन दर टोकन पार्स करता है और संरचना को भरता है।
  6. \n
\n\n

लाभ — आप पूरे JSON को मेमोरी में संग्रहीत नहीं करते हैं। नुकसान — बफ़र प्रबंधन और स्ट्रीम रीडिंग पर थोड़ा अधिक ओवरहेड।

\n\n

प्रयोग: बेंचमार्क झूठ नहीं बोलते

\n\n

आइए सिद्धांत को व्यवहार में जाँचें। हम तीन परिदृश्यों के लिए एक सरल बेंचमार्क लिखेंगे:

\n
    \n
  • छोटा JSON (1 KB)
  • \n
  • मध्यम JSON (100 KB)
  • \n
  • बड़ा JSON (10 MB)
  • \n
\n\n
package main\n\nimport (\n    "bytes"\n    "encoding/json"\n    "testing"\n)\n\ntype Data struct {\n    ID    int    `json:"id"`\n    Name  string `json:"name"`\n    Items []int  `json:"items"`\n}\n\nfunc generateJSON(size int) []byte {\n    data := Data{\n        ID:    1,\n        Name:  "test",\n        Items: make([]int, size),\n    }\n    for i := 0; i < size; i++ {\n        data.Items[i] = i\n    }\n    b, _ := json.Marshal(data)\n    return b\n}\n\nfunc BenchmarkUnmarshal(b *testing.B) {\n    jsonData := generateJSON(1000) // 1 KB\n    var result Data\n    for i := 0; i < b.N; i++ {\n        json.Unmarshal(jsonData, &result)\n    }\n}\n\nfunc BenchmarkDecoder(b *testing.B) {\n    jsonData := generateJSON(1000) // 1 KB\n    var result Data\n    for i := 0; i < b.N; i++ {\n        reader := bytes.NewReader(jsonData)\n        json.NewDecoder(reader).Decode(&result)\n    }\n}
\n\n

परिणाम (मेरे लैपटॉप पर, Go 1.22):

\n\n\n \n
आकार

ब्लॉग

पुस्तक अनुशंसाएँ