უკან დაბრუნება
JSON-ის ობიექტების პარსინგი შუალედური AST-ის გარეშე
SiTech AI Team2 წთ. საკითხავი

JSON-ის ობიექტების პარსინგი შუალედური AST-ის გარეშე

ბლოგპოსტში ავტორი აჩვენებს, როგორ შეიძლება JSON-ის ობიექტები პირდაპირ დომენურ ტიპებში დაპარსოს ნახევრად ინიციალიზებული მნიშვნელობის გამოყენებით, AST-ის გარეშე. მიკრო-ბენჩმარკები დაახლოებით სამჯერ უფრო მაღალ სიჩქარეს აჩვენებს.

JSON-ის ბიბლიოთეკების უმეტესობა ერთსა და იმავე ორეტაპიან სქემას მიჰყვება: ჯერ ნედლ ბაიტებს შუალედურ ხეში — AST-ში — გადააქცევს, შემდეგ კი ამ ხეზე გავლით აგებს იმ მონაცემთა ტიპებს, რომლებსაც აპლიკაცია რეალურად იყენებს. arthi-chaud.github.io-ზე გამოქვეყნებული ბლოგპოსტი სვამს კითხვას, რა მოხდება, თუ შუალედურ ხეს სრულად მოვაშორებთ, და ნახევრად ინიციალიზებულ მნიშვნელობებზე დაფუძნებულ მიდგომას გვთავაზობს.

რატომ ღირს შუალედური წარმოდგენა ძვირად

ავტორი ჩვეულ დიზაინს ორ საფეხურად აღწერს: პარსერი ByteString-ს JSON-ის AST-ად აქცევს, ცალკე ფუნქცია — მაგალითად fromJSON — კი ამ AST-ს დომენურ მონაცემად, მაგალითად Album-ის ჩანაწერად, გარდაქმნის. განცალკევება მოსახერხებელია: პარსინგი ვალიდაციისგან დამოუკიდებელი რჩება, გარდაქმნის კოდი კი ხშირად ავტომატურადაც გენერირდება Template Haskell-ის ან Generics-ის მეშვეობით. თუმცა უფასო არ არის — AST დამატებითი ობიექტია მეხსიერებაში, სულ მცირე იმდენივე ზომის, რამდენიც საბოლოო მნიშვნელობა, და მისი აგება ზედმეტ გამოთვლას მოითხოვს, რომელიც დომენური ობიექტის შექმნისთანავე უქმდება.

ნახევრად ინიციალიზებული ობიექტი და ბიტების მთვლელი

ალტერნატივა მდგომარეობს იმაში, რომ ნახევრად ინიციალიზებული დომენური ობიექტი თავად პარსერს გადაეცეს და ველები წაკითხვისთანავე ჩაიწეროს — AST საერთოდ არ იქმნება. Haskell-ში ეს სიზარმაცეს ეყრდნობა: ყველა ველი undefined-ით ინიციალიზდება, ამიტომ სამიზნე ტიპის ველები non-strict უნდა იყოს. უსაფრთხოებას ბიტების სიმრავლე აბრუნებს — Word64, რომელიც maxBound-ით იწყება: ველის ჩაწერისას მისი პოზიციის ბიტი იშლება, პარსინგის დასრულებისას კი ნულოვანი მნიშვნელობა ადასტურებს, რომ ობიექტი სრულად ინიციალიზებულია. წინააღმდეგ შემთხვევაში პარსერი ვარდება და გამოტოვებულ ველებს ასახელებს; Maybe ტიპის ველებს კი Nothing-ის მინიჭება საკმარისია.

ბენჩმარკები და შეზღუდვები

პროტოტიპი Haskell-ის flatparse ბიბლიოთეკითაა აწყობილი, სადაც სპეციალიზებულ პარსერებს კომპილაციის დროს Template Haskell აგენერირებს. Criterion-ის მიკრო-ბენჩმარკებში, Intel-ის მანქანაზე ორი Xeon Gold 6244 პროცესორით და 32 გბ RAM-ით, aeson — Haskell-ის მთავარი JSON ბიბლიოთეკა — წიგნისთვის 1.051 μs-ს, ავტორისთვის წიგნების სიით კი 2.901 μs-ს აჩვენებს. იგივე ბიბლიოთეკა შუალედური AST-ით 922.7 ns და 2.813 μs-ია, AST-ის გარეშე კი 314.2 ns და 1.027 μs — დაახლოებით სამჯერ სწრაფად. ავტორი აღნიშნავს, რომ პარსერი JSON-ის სტანდარტს სრულად არ შეესაბამება და რომ მიკრო-ბენჩმარკები რეალურ აპლიკაციებს ყოველთვის არ ასახავს.

რას აჩვენებს ექსპერიმენტი

პოსტი ხაზგასმით აღნიშნავს, რომ შუალედური წარმოდგენების წინააღმდეგ არ არის — ისინი პარსინგს ვალიდაციისგან აცალკევებენ და კოდს უფრო ადვილად შესანარჩუნებელს ხდიან. საუბარია ამ განცალკევების ღირებულებაზე: ორი საფეხურის გაერთიანება ნაკლებად ელეგანტური, მაგრამ მუშა კომპრომისია. იდეა ახალი არ არის: Rust-ის serde staged პროგრამირებით ამ ფენას კომპილაციის დროზე გადააქვს, მკაცრ ენებში კი იგივე ხერხი undefined-ის ნაცვლად ცარიელი მნიშვნელობებით იწყება.

SSiTech

SiTech — AI-გაძლიერებული ვებ დეველოპმენტი

ვქმნით სწრაფ, თანამედროვე ვებსაიტებს და AI-ს ვაერთიანებთ ქართული ბიზნესებისთვის. გაქვთ პროექტი ან კითხვა? სიამოვნებით დაგეხმარებით.