सामान्य रूप से लेसिक बाइंडिंग बनाम डायनेमिक बाइंडिंग
निम्नलिखित उदाहरण पर विचार करें:
(let ((lexical-binding nil))
(disassemble
(byte-compile (lambda ()
(let ((foo 10))
(message foo))))))
यह संकलन करता है और तुरंत lambda
एक स्थानीय चर के साथ एक सरल को मिटा देता है। lexical-binding
ऊपर के रूप में विकलांग के साथ , बाइट कोड निम्नानुसार दिखता है:
0 constant 10
1 varbind foo
2 constant message
3 varref foo
4 call 1
5 unbind 1
6 return
नोट varbind
और varref
निर्देश। ये निर्देश ढेर स्मृति पर एक वैश्विक बाध्यकारी वातावरण में उनके नाम से क्रमशः चर और बाँधते हैं । यह सब प्रदर्शन पर प्रतिकूल प्रभाव डालता है: इसमें स्ट्रिंग हैशिंग और तुलना , वैश्विक डेटा एक्सेस के लिए सिंक्रनाइज़ेशन , और दोहराया हीप मेमोरी एक्सेस शामिल है जो सीपीयू कैशिंग के साथ बुरी तरह से खेलता है। इसके अलावा, डायनामिक वैरिएबल बाइंडिंग को अपने पिछले वैरिएबल के अंत में पुनर्स्थापित करने की आवश्यकता होती है , जो बिंदी के साथ प्रत्येक ब्लॉक के लिए अतिरिक्त लुकअप जोड़ता है ।let
n
let
n
यदि आप बाँध lexical-binding
के t
ऊपर के उदाहरण में, बाइट कोड कुछ भिन्न दिखेगा:
0 constant 10
1 constant message
2 stack-ref 1
3 call 1
4 return
ध्यान दें कि varbind
और varref
पूरी तरह से चले गए हैं। स्थानीय चर को केवल स्टैक पर धकेल दिया जाता है, और stack-ref
निर्देश के माध्यम से एक स्थिर ऑफसेट द्वारा संदर्भित किया जाता है । अनिवार्य रूप से, चर बाध्य है और लगातार समय के साथ पढ़ा जाता है , इन-स्टैक मेमोरी पढ़ता है और लिखता है, जो पूरी तरह से स्थानीय है और इस तरह से संगामिति और सीपीयू कैशिंग के साथ अच्छा खेलता है , और इसमें कोई तार शामिल नहीं है।
आम तौर पर, (उदाहरण के लिए स्थानीय चर का शाब्दिक बाध्यकारी लुकअप के साथ let
, setq
, आदि) बहुत कम क्रम और स्मृति जटिलता ।
यह विशिष्ट उदाहरण है
डायनामिक बाइंडिंग के साथ, प्रत्येक को उपरोक्त कारणों से एक प्रदर्शन दंड दिया जाता है। अधिक देता है, अधिक गतिशील चर बाइंडिंग।
विशेष रूप से, शरीर के let
भीतर एक अतिरिक्त के साथ loop
, बाउंड चर को लूप के प्रत्येक पुनरावृत्ति पर बहाल करना होगा, प्रत्येक पुनरावृत्ति के लिए एक अतिरिक्त चर लुकअप को जोड़ना होगा । इसलिए, यह लूप बॉडी से बाहर रखने के लिए तेज़ है, ताकि संपूर्ण लूप समाप्त होने के बाद पुनरावृति चर केवल एक बार रीसेट हो। हालाँकि, यह विशेष रूप से सुरुचिपूर्ण नहीं है, क्योंकि पुनरावृत्ति चर बाउंड तरीका है इससे पहले कि यह वास्तव में आवश्यक है।
लेक्सिकल बाइंडिंग के साथ, let
एस सस्ते हैं। विशेष रूप से, एक let
लूप बॉडी के भीतर लूप बॉडी के let
बाहर की तुलना में बदतर (प्रदर्शन-वार) नहीं है । इसलिए, चरों को स्थानीय रूप से बाँधना पूरी तरह से ठीक है, और लूप बॉडी तक सीमित होने वाले वैरिएबल वैरिएबल को रखना।
यह थोड़ा तेज़ भी है, क्योंकि यह बहुत कम निर्देशों का संकलन करता है। साइड-बाय-साइड डिस्सैम्ड के बाद के भाग पर विचार करें (दाईं ओर स्थानीय लेट):
0 varref list 0 varref list
1 constant nil 1:1 dup
2 varbind it 2 goto-if-nil-else-pop 2
3 dup 5 dup
4 varbind temp 6 car
5 goto-if-nil-else-pop 2 7 stack-ref 1
8:1 varref temp 8 cdr
9 car 9 discardN-preserve-tos 2
10 varset it 11 goto 1
11 varref temp 14:2 return
12 cdr
13 dup
14 varset temp
15 goto-if-not-nil 1
18 constant nil
19:2 unbind 2
20 return
मेरे पास कोई सुराग नहीं है, हालांकि, क्या अंतर पैदा कर रहा है।
varbind
लेक्सिकल बाइंडिंग के तहत संकलित कोड में नहीं है। यही संपूर्ण बिंदु और उद्देश्य है।