
ניתוח אובייקטי JSON בלי AST ביניים
פוסט בבלוג מציג גישה שבה אובייקטי JSON מנותחים ישירות לטיפוסי הדומיין באמצעות ערך מאותחל חלקית, בלי עץ AST ביניים. המיקרו־בנצ'מרקים מראים מהירות גבוהה פי שלושה בערך, אך המחבר מדגיש שהשיטה פחות אלגנטית.
רוב ספריות ה-JSON עובדות לפי אותה שיטה דו-שלבית: תחילה הן מנתחות את הבתים הגולמיים לעץ ביניים שמשקף את המסמך, ואחר כך עוברות על העץ כדי לבנות את טיפוסי הנתונים שהאפליקציה באמת משתמשת בהם. פוסט בבלוג באתר arthi-chaud.github.io שואל מה יקרה אם נסיר את עץ הביניים לחלוטין, ומציע גישה המבוססת על ערכים מאותחלים חלקית.
מה עולה הייצוג הביניים
המחבר מתאר את העיצוב המקובל כצינור: מנתח הופך ByteString ל-AST של JSON, ופונקציה נפרדת כמו fromJSON הופכת את ה-AST לנתוני דומיין, למשל רשומת Album. ההפרדה נוחה — הניתוח נשאר בלתי תלוי בוולידציה, ואת קוד ההמרה אפשר לרוב לייצר אוטומטית עם Template Haskell או Generics — אבל היא לא בחינם: ה-AST הוא אובייקט נוסף בזיכרון, שגודלו לפחות כגודל הערך הסופי, ובנייתו דורשת מחשוב שנזרק ברגע שאובייקט הדומיין נוצר.
אובייקטים מאותחלים חלקית ומונה ביטים
החלופה מעבירה אובייקט דומיין מאותחל חלקית דרך המנתח עצמו, כך שהשדות נכתבים מיד עם קריאתם ואף AST לא נבנה. ב-Haskell זה נשען על עצלות: כל שדה מאותחל ל-undefined, ולכן השדות של טיפוס המטרה אסור שיהיו קפדניים. את הבטיחות מחזיר סט ביטים — Word64 המאותחל ל-maxBound. כתיבת שדה מנקה את הביט במיקומו בהגדרת הטיפוס, ובסיום הניתוח ערך אפס מעיד שהאובייקט מאותחל במלואו. אחרת המנתח נכשל ויכול לפרט את השדות החסרים בהודעת השגיאה, בעוד שדות מטיפוס Maybe אפשר פשוט להציב ל-Nothing.
בנצ'מרקים ומגבלות
ההוכחה-לכאורה נבנתה עם הספרייה flatparse, כש-Template Haskell מייצר מנתחים מותאמים בזמן קומפילציה. במיקרו-בנצ'מרקים של Criterion על מחשב Intel עם שני מעבדי Xeon Gold 6244 ו-32 ג'יגה זיכרון, הספרייה aeson — ספריית ה-JSON המרכזית של Haskell — מדדה 1.051 μs לספר ו-2.901 μs למחבר עם רשימת ספרים. אותה ספרייה עם AST ביניים: 922.7 ns ו-2.813 μs; בלי AST: 314.2 ns ו-1.027 μs — פי שלושה בערך מהר יותר. המחבר מציין שהמנתח אינו תואם לחלוטין למפרט JSON, ושמיקרו-בנצ'מרקים לא תמיד משקפים יישומים אמיתיים.
מה מלמד הניסוי
הפוסט מבהיר שאין כאן ביקורת על ייצוגים ביניים: הם מפרידים בין הניתוח לוולידציה ושומרים על קוד שניתן לתחזוקה. הנקודה היא המחיר שלהם בזמן ריצה, ושמיזוג שני השלבים הוא פשרה פחות אלגנטית אך עובדת כשהמהירות חשובה. הרעיון גם אינו חדש: מסגרת הסריאליזציה של Rust, serde, מעבירה את השכבה הביניים לזמן קומפילציה באמצעות staged programming, ובשפות קפדניות אפשר להתחיל מערכים ריקים במקום undefined.
SiTech — פיתוח אתרים בכוח ה-AI
אנחנו בונים אתרים מהירים ומודרניים ומשלבים AI בתהליכי עבודה אמיתיים. יש לכם פרויקט או שאלה? נשמח לעזור.