Diğerlerinin dediği gibi, önce programınızın performansını ölçmelisiniz ve muhtemelen uygulamada bir fark bulamayacaksınız.
Yine de, kavramsal bir düzeyde, sorunuzla ilgili birkaç şeyi açıklığa kavuşturacağımı düşündüm. İlk önce şunu sorarsınız:
Modern derleyicilerde işlev çağrısı maliyetleri hala önemli mi?
"Function" ve "compilers" anahtar kelimelerine dikkat edin. Teklifiniz farklıdır:
Bir yöntem çağrısının ücretinin, dile bağlı olarak önemli olabileceğini unutmayın.
Bu, nesneye yönelik anlamda yöntemlerden bahsediyor .
"İşlev" ve "yöntem" çoğu zaman birbirinin yerine kullanılırken, maliyetlerine (sorduğunuz) ve derlemeye gelince (verdiğiniz bağlam) olduğu gibi farklılıklar vardır.
Özellikle, dinamik gönderime karşı statik gönderimi bilmemiz gerekir . Şimdilik optimizasyonları görmezden geleceğim.
C gibi bir dilde, genellikle diyoruz fonksiyonları ile statik sevk . Örneğin:
int foo(int x) {
return x + 1;
}
int bar(int y) {
return foo(y);
}
int main() {
return bar(42);
}
Derleyici çağrıyı gördüğünde, foo(y)
bu foo
ismin hangi fonksiyondan bahsettiğini bilir , böylece çıkış programı doğrudan foo
ucuza atlar . Yani ne statik sevk anlamına gelir.
Alternatiftir dinamik sevk derleyici, gelmez çağrılan hangi işlevi biliyoruz. Örnek olarak, bazı Haskell kodu (C eşdeğeri karışık olduğu için!):
foo x = x + 1
bar f x = f x
main = print (bar foo 42)
Burada bar
işlev, f
herhangi bir şey olabilecek argümanını çağırıyor . Dolayısıyla derleyici sadece bar
hızlı bir atlama komutunu derleyemez, çünkü nereye atlayacağını bilmiyor. Bunun yerine, oluşturduğumuz kod, hangi işlevi işaret ettiğini bulmak ve sonra ona atlamak için uygun bar
görmeyecektir f
. Yani ne dinamik bir gönderme anlamına gelir.
Bu örneklerin her ikisi de işlevler içindir . Dinamik olarak gönderilen işlevin belirli bir stili olarak düşünülebilecek yöntemlerden bahsettiniz . Örneğin, işte bazı Python:
class A:
def __init__(self, x):
self.x = x
def foo(self):
return self.x + 1
def bar(y):
return y.foo()
z = A(42)
bar(z)
y.foo()
O değerini yukarıya bakıyor beri çağrı, dinamik sevkini kullanır foo
mülkiyet y
nesnesi, ve bulduğu her ne aradığını; y
sınıfın olacağını A
veya A
sınıfın bir foo
yöntem içerdiğini bilmiyor , bu yüzden doğrudan atlayamayız.
Tamam, temel fikir bu. Derleme veya yorumlamadan bağımsız olarak , statik gönderimin dinamik gönderimden daha hızlı olduğunu unutmayın ; Her şey eşit. Değişikliklerden herhangi bir şekilde ek ücret alınır.
Peki bu, modernleştirici derleyicileri nasıl etkiliyor?
Unutulmaması gereken ilk şey, statik gönderimin daha yoğun bir şekilde optimize edilebileceği: hangi fonksiyona atladığımızı bildiğimizde, satır içi gibi şeyler yapabilir. Dinamik gönderimde, çalışma zamanına kadar zıpladığımızı bilmiyoruz, bu yüzden yapabileceğimiz fazla bir optimizasyon yok.
İkinci olarak, bazı diller için de mümkündür sonucuna bazı dinamik gönderir atlama sona erecek nerede ve dolayısıyla statik sevk içine onları optimize. Bu, satır içi vb. Diğer optimizasyonları yapmamızı sağlar.
Yukarıdaki Python örneğinde, bu tür bir çıkarım oldukça ümitsizdir, çünkü Python, diğer kodların sınıfları ve özellikleri geçersiz kılmasına izin verir;
Dilimiz daha fazla kısıtlama getirmemize izin veriyorsa, örneğin bir ek açıklama kullanarak y
sınıfa sınırlama yaparak A
, bu bilgiyi hedef işlevi ortaya çıkarmak için kullanabiliriz. Alt sınıflara sahip dillerde (bu, neredeyse tüm sınıfların dilidir!) Aslında yeterli değildir, çünkü y
aslında farklı (alt) bir sınıfa sahip olabilir, bu yüzden final
tam olarak hangi fonksiyonun çağrılacağını bilmek için Java'nın ek açıklamaları gibi ek bilgilere ihtiyaç duyarız .
Haskell OO dil değildir, ancak değerini anlaması f
inlining ile bar
(edildiği statik dağıtılacak) main
ikame foo
için y
. Hedef yana foo
in main
bu işlevler küçük olduğu için statik olarak bilinir, çağrı statik olarak gönderilir olur ve muhtemelen de satır içi alacak ve tamamen uzak optimize (derleyici onları satır içi olasılığı daha yüksektir, biz genel olarak bu konuda sayılmaz rağmen ).
Dolayısıyla maliyet aşağıya düşer:
- Dil aramanızı statik mi yoksa dinamik olarak mı gönderiyor?
- İkincisi ise, dil, uygulamanın başka bilgileri kullanarak (örneğin, türler, sınıflar, ek açıklamalar, satır içi, vb.) Hedefi hedeflemesine izin veriyor mu?
- Statik gönderme (çıkarım veya başka şekilde) ne kadar agresif bir şekilde optimize edilebilir?
"Çok dinamik" bir dil kullanıyorsanız, çok fazla dinamik gönderim ve derleyicinin kullanabileceği birkaç garanti varsa, o zaman her çağrı bir ücrete tabidir. "Çok statik" bir dil kullanıyorsanız, olgun bir derleyici çok hızlı bir kod üretecektir. Arasındaysanız, kodlama stilinize ve uygulamanın ne kadar akıllı olduğuna bağlı olabilir.