Liên kết từ điển so với ràng buộc động nói chung
Hãy xem xét ví dụ sau:
(let ((lexical-binding nil))
(disassemble
(byte-compile (lambda ()
(let ((foo 10))
(message foo))))))
Nó biên dịch và ngay lập tức phân tách một đơn giản lambdavới một biến cục bộ. Với lexical-bindingvô hiệu hóa, như trên, mã byte trông như sau:
0 constant 10
1 varbind foo
2 constant message
3 varref foo
4 call 1
5 unbind 1
6 return
Lưu ý varbindvà varrefhướng dẫn. Các hướng dẫn này liên kết và tra cứu các biến tương ứng theo tên của chúng trong môi trường liên kết toàn cầu trên bộ nhớ heap . Tất cả điều này có ảnh hưởng xấu đến hiệu suất: Nó bao gồm băm và so sánh chuỗi , đồng bộ hóa để truy cập dữ liệu toàn cầu và truy cập bộ nhớ heap lặp đi lặp lại , điều này rất tệ với bộ nhớ đệm CPU. Ngoài ra, các ràng buộc biến động cần phải được khôi phục về biến trước đó của chúng ở cuối let, điều này bổ nsung thêm tra cứu cho mỗi letkhối với ncác ràng buộc.
Nếu bạn ràng buộc lexical-bindingđể ttrong ví dụ trên, các mã byte trông hơi khác:
0 constant 10
1 constant message
2 stack-ref 1
3 call 1
4 return
Lưu ý rằng varbindvà varrefhoàn toàn biến mất. Biến cục bộ chỉ đơn giản được đẩy lên ngăn xếp và được gọi bằng một giá trị bù không đổi thông qua stack-refhướng dẫn. Về cơ bản, biến bị ràng buộc và đọc với thời gian không đổi , bộ nhớ trong ngăn xếp đọc và ghi, hoàn toàn cục bộ và do đó chơi tốt với bộ đệm đồng thời và bộ đệm CPU , và không liên quan đến bất kỳ chuỗi nào.
Nói chung, với tra cứu từ vựng ràng buộc của các biến địa phương (ví dụ let, setqvv) có ít thời gian chạy và bộ nhớ phức tạp .
Ví dụ cụ thể này
Với ràng buộc động, mỗi người sẽ phải chịu một hình phạt hiệu suất, vì những lý do trên. Càng cho phép, các ràng buộc biến động càng nhiều.
Đáng chú ý, với một bổ sung lettrong loopcơ thể, biến bị ràng buộc sẽ cần phải được khôi phục ở mỗi lần lặp của vòng lặp , thêm một tra cứu biến bổ sung cho mỗi lần lặp . Do đó, nhanh hơn để giữ cho phép thoát khỏi thân vòng lặp, do đó biến lặp chỉ được đặt lại một lần , sau khi toàn bộ vòng lặp kết thúc. Tuy nhiên, điều này không đặc biệt tao nhã, vì biến lặp được ràng buộc theo cách trước khi nó thực sự được yêu cầu.
Với ràng buộc từ vựng, lets là giá rẻ. Đáng chú ý, một thân lettrong vòng lặp không tệ hơn (hiệu năng thông minh) so với letbên ngoài thân vòng lặp. Do đó, việc liên kết các biến cục bộ càng tốt càng tốt và giữ biến lặp được giới hạn trong thân vòng lặp.
Nó cũng nhanh hơn một chút, vì nó biên dịch theo hướng dẫn ít hơn nhiều. Xem xét việc tháo gỡ bên cạnh theo sau (cục bộ ở bên phải):
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
Tôi không có manh mối, mặc dù, những gì gây ra sự khác biệt.
varbindmã được biên dịch theo ràng buộc từ vựng. Đó là toàn bộ quan điểm và mục đích.