Genel olarak dinamik bağlamaya karşı sözcüksel bağlanma
Aşağıdaki örneği düşünün:
(let ((lexical-binding nil))
(disassemble
(byte-compile (lambda ()
(let ((foo 10))
(message foo))))))
lambdaYerel bir değişkeni olan basit bir nesneyi derler ve hemen demonte eder . İle lexical-bindingengelli yukarıdaki gibi, bayt kod görünüyor şöyle:
0 constant 10
1 varbind foo
2 constant message
3 varref foo
4 call 1
5 unbind 1
6 return
Not varbindve varreftalimatları. Bu talimatlar bağlamak ve arama sırasıyla değişkenler kendi adıyla bir de küresel üzerindeki bağlanma çevre yığın belleğe . Bütün bunlar performans üzerinde olumsuz bir etkiye sahiptir: Dize hashini ve karşılaştırmasını , global veri erişimi için senkronizasyonu ve CPU önbelleklemesi ile kötü oynayan tekrarlanan yığın bellek erişimini içerir. Ayrıca, dinamik değişken bağlantılarının , sonunda bağları olan her blok için ek aramalar ekleyen, önceki değişkenlerine geri getirilmesi gerekir .letnletn
Eğer bağlama lexical-bindingiçin tyukarıdaki örnekte, bayt kod biraz farklı görünüyor:
0 constant 10
1 constant message
2 stack-ref 1
3 call 1
4 return
Bunu varbindve varreftamamen gittiğini unutmayın. Yerel değişken basitçe istifin üzerine itilir ve stack-refkomut aracılığıyla sabit bir ofset ile ifade edilir . Esas olarak, değişken bağlanmış ile okunur sabit zamanda , içinde yığın bellek okur ve böylece tamamen yerel ve yazma, eşzamanlılık ve CPU önbelleğe alma ile de oynar ve hiç bir dizeleri anlamına gelmez.
Genel olarak, yerel değişkenlerin sözcük bağlanma aramaları (örn ile let, setqvs.) sahip çok daha az çalışma zamanı ve bellek karmaşıklığı .
Bu özel örnek
Dinamik bağlamada, her biri yukarıdaki sebeplerden dolayı bir performans cezasına çarptırılır. Ne kadar çok olursa, değişken değişken bağlamalar o kadar fazla olur.
Özellikle, gövde letiçinde bir ek ile loop, sınır değişkeninin, her bir yinelemeye ek bir değişken araması ekleyerek , döngünün her yinelemesinde geri yüklenmesi gerekir . Bu nedenle, döngü gövdesinden uzak tutulması daha hızlıdır, böylece yineleme değişkeni tüm döngü bittikten sonra yalnızca bir kez sıfırlanır . Bununla birlikte, bu özellikle zarif değildir, çünkü yineleme değişkeni gerçekte gerekmeden önce bağlanır.
Sözlüksel bağlamayla, lets ucuzdur. Özellikle, bir letilmek gövdesi içindeki bir ilmek, ilmek gövdesinin letdış yüzeyinden daha kötü değildir (performans açısından) . Bu nedenle, değişkenleri olabildiğince yerel olarak bağlamak ve yineleme değişkeninin döngü gövdesiyle sınırlı kalması tamamen iyidir.
Aynı zamanda biraz daha hızlı, çünkü daha az talimat alıyor. Takip eden yan yana sökmeyi göz önünde bulundurun (sağ taraftaki yerel izin):
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
Ne var ki, aradaki farka neden olan hiçbir fikrim yok.
varbindSözcüksel bağlanma altında derlenmiş kod yoktur . Bütün amaç ve amaç bu.