การรวมคำศัพท์กับการเชื่อมแบบไดนามิกโดยทั่วไป
ลองพิจารณาตัวอย่างต่อไปนี้:
(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
คำแนะนำ คำแนะนำเหล่านี้ผูกและค้นหาตามลำดับตัวแปรโดยชื่อของพวกเขาในโลกสภาพแวดล้อมที่มีผลผูกพันในหน่วยความจำกอง ทั้งหมดนี้มีผลกระทบต่อประสิทธิภาพการทำงาน: มันเกี่ยวข้องกับการhashing สตริงและการเปรียบเทียบ , ประสานสำหรับการเข้าถึงข้อมูลทั่วโลกและทำซ้ำเข้าถึงหน่วยความจำกองที่เล่นไม่ดีกับแคช CPU นอกจากนี้การผูกตัวแปรแบบไดนามิกจำเป็นต้องถูกเรียกคืนเป็นตัวแปรก่อนหน้า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
คำสั่ง โดยพื้นฐานแล้วตัวแปรที่ถูกผูกไว้และอ่านด้วยเวลาคง , ในกองหน่วยความจำอ่านและเขียนซึ่งเป็นท้องถิ่นอย่างสิ้นเชิงและทำให้เล่นได้ดีกับการทำงานพร้อมกันและแคช CPUและไม่เกี่ยวข้องกับสตริงใด ๆ เลย
โดยทั่วไปที่มีการค้นหาคำศัพท์ที่มีผลผูกพันของตัวแปรท้องถิ่น (เช่นlet
, setq
ฯลฯ ) มีมากน้อยรันไทม์และหน่วยความจำความซับซ้อน
ตัวอย่างเฉพาะนี้
ด้วยการเชื่อมโยงแบบไดนามิกแต่ละรายการจะได้รับโทษประสิทธิภาพด้วยเหตุผลด้านบน ยิ่งช่วยให้มีการผูกตัวแปรแบบไดนามิกมากขึ้น
โดยเฉพาะอย่างยิ่งที่มีการเพิ่มเติมlet
ภายในloop
ร่างกายตัวแปรที่ถูกผูกไว้จะต้องได้รับการบูรณะที่ซ้ำของวงทุก , เพิ่มการค้นหาตัวแปรเพิ่มเติมเพื่อให้แต่ละซ้ำ ดังนั้นจึงเป็นการเร็วกว่าที่จะป้องกันการปล่อยให้ออกจากร่างกายลูปเพื่อให้ตัวแปรการวนซ้ำถูกรีเซ็ตเพียงครั้งเดียวหลังจากการวนซ้ำทั้งหมดเสร็จสิ้น อย่างไรก็ตามนี่ไม่ได้สวยงามโดยเฉพาะเนื่องจากตัวแปรการวนซ้ำนั้นถูกผูกไว้ก่อนที่จะต้องใช้จริง
ด้วยการรวมคำศัพท์let
s มีราคาถูก ยวด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
รหัสในการรวบรวมภายใต้การผูกคำ นั่นคือจุดรวมและวัตถุประสงค์