Zaten büyük cevaplarla bu soru-cevapın sonuncusu, ama şeyleri hafızada bit ve bayt açısından bakarken kullanılan bir yabancı olarak davetsiz misafir olmak istedim.
Değişmez tasarımlar, hatta bir C perspektifinden geldiğim için ve bugünlerde sahip olduğumuz bu canavarca donanımı etkin bir şekilde programlamak için yeni yollar bulma perspektifinden çok heyecanlıyım.
Yavaş / Hızlı
İşleri yavaşlatıp yavaşlatmadığı sorusuna gelince, robotik bir cevap olurdu yes
. Bu tür çok teknik kavramsal düzeyde, değişmezlik sadece işleri yavaşlatabilirdi. Donanım, sporadik olarak bellek tahsis etmediğinde en iyisini yapar ve bunun yerine mevcut belleği değiştirebilir (neden geçici konum gibi kavramlarımız var).
Oysa pratik bir cevap maybe
. Performans hala büyük ölçüde önemsiz olmayan herhangi bir kod tabanında bir verimlilik ölçütüdür. Genellikle hataları göz ardı etmemize rağmen, yarış koşulları üzerinde tetiklenen en korkunç kod tabanlarını en verimli bulmuyoruz. Verimlilik genellikle zarafetin ve sadeliğin bir işlevidir. Mikro optimizasyonların zirvesi biraz çelişkili olabilir, ancak bunlar genellikle kodun en küçük ve en kritik bölümleri için ayrılmıştır.
Değiştirilebilir Bitleri ve Baytları Dönüştürme
Biz gibi kavramları, x-ray ise, düşük seviyeli açısından geliyor objects
ve strings
bunun merkezinde, benzeri ve farklı hız / boyutu özelliklerine sahip çeşitli bellek form (hız ve bellek donanımın bir boyutu, tipik haliyle sadece bit ve bayt karşılıklı dışlama).
Bilgisayarın bellek hiyerarşisi, yukarıdaki şemada olduğu gibi aynı bellek belleğine tekrar tekrar erişmemizden hoşlanır, çünkü sık erişilen bellek yığınını en hızlı bellek biçiminde (L1 önbellek, ör. neredeyse bir sicil kadar hızlıdır). Tam olarak aynı belleğe tekrar tekrar erişebilir (defalarca tekrar kullanarak) ya da topluluğun farklı bölümlerine art arda erişebiliriz (örneğin: o bellek topluluğunun çeşitli bölümlerine art arda erişen bitişik bir topaktaki öğeler arasında döngü).
Bu hafızayı değiştirmek, yandan tamamen yeni bir hafıza bloğu oluşturmak istemekle sonuçlanırsa, bu süreçte bir İngiliz anahtarı fırlatırız.
... bu durumda, yeni bellek bloğuna erişmek zorunlu sayfa hataları gerektirebilir ve en hızlı bellek biçimlerine geri dönmek için önbellek özlüyor olabilir (tümüyle bir kayıt defterine). Bu gerçek bir performans katili olabilir.
Bununla birlikte, önceden dokunulan, önceden dokunulan bellek deposunu kullanan, bunu azaltmanın yolları var.
Büyük agrega
Biraz daha üst düzey bir bakış açısıyla ortaya çıkan başka bir kavramsal konu, sadece gerçekten büyük agregaların gereksiz kopyalarını toplu olarak yapmaktır.
Aşırı karmaşık bir diyagramdan kaçınmak için, bu basit bellek bloğunun bir şekilde pahalı olduğunu düşünelim (inanılmaz derecede sınırlı bir donanımda belki UTF-32 karakterler olabilir).
Bu durumda, "YARDIM" ı "KILL" ile değiştirmek istiyorsak ve bu bellek bloğu değiştirilemezse, tamamen yeni bir blok oluşturmak zorunda kalacağız. :
Hayal gücümüzü biraz esnetmek, sadece küçük bir parçayı benzersiz kılmak için her şeyin bu tür derin bir kopyası oldukça pahalı olabilir (gerçek dünyadaki durumlarda, bu bellek bloğu bir problem yaratacak kadar büyük olurdu).
Bununla birlikte, böyle bir masrafa rağmen, bu tür bir tasarım insan hatasına çok daha az eğilimli olacaktır. Saf fonksiyonlarla işlevsel bir dilde çalışan herkes muhtemelen bunu takdir edebilir ve özellikle de dünyaya dikkat etmeden bu kodu çok okuyabildiğimiz çok iş parçacıklı durumlarda. Genel olarak, insan programcıları durum değişimleri üzerinde, özellikle de geçerli bir işlevin kapsamı dışındaki durumlara dış yan etkilere neden olanları açma eğilimindedir. Böyle bir durumda harici bir hatadan (istisna) kurtulmak bile, karışımdaki değişken harici durum değişiklikleriyle inanılmaz derecede zor olabilir.
Bu gereksiz kopyalama çalışmasını azaltmanın bir yolu, bu bellek bloklarını karakterlere bir işaretçi (ya da referanslar) koleksiyonu haline getirmektir.
Özür dilerim, L
diyagramı çizerken benzersiz olmamamız gerekmediğinin farkında değildim .
Mavi, sığ kopyalanmış verileri gösterir.
... ne yazık ki, bu karakter başına bir işaretçi / referans maliyet ödemek için inanılmaz derecede pahalı olacaktır. Dahası, karakterlerin içeriğini adres alanının her yerine yayabilir ve bunun için bir sayfa dolusu sayfa hatası ve önbellek özeti şeklinde ödeme yapabiliriz, bu çözümü kolayca bütününü kopyalamaktan daha da kötü hale getirebiliriz.
Bu karakterleri bitişik olarak tahsis etmemize dikkat etsek bile, makine bir karaktere 8 karakter ve 8 imleci önbellek satırına yükleyebilir. Yeni dizgiyi geçmek için bu şekilde bellek yüklüyoruz:
Bu durumda, ideal olarak sadece 3'e ihtiyaç duyduğumuzda, bu diziyi geçmek için yüklenecek 7 farklı önbellek satırı, bitişik belleğe ihtiyaç duyarız.
Verileri Topla
Yukarıdaki sorunu hafifletmek için, aynı temel stratejiyi uygulayabiliriz, ancak 8 karakterden oluşan kaba bir seviyede uygulayabiliriz;
Sonuç, teorik optimumun sadece 1 kısa olan bu diziyi aşmak için 4 değerde veri önbelleği (3 işaretçi için 1 ve karakter için 3) değerinin yüklenmesini gerektirir.
Yani hiç fena değil. Hafıza kaybı var ama hafıza bol ve daha fazla kullanmak, fazladan belleğe sık erişilemeyen bir veriye sahip olacaksa işleri yavaşlatmıyor. Yalnızca, azaltılmış bellek kullanımı ve hızının sık sık el ele gittiği, tek bir sayfaya veya önbellek satırına daha fazla bellek sığdırıp boşaltmadan önce hepsine erişmek istediğimiz sıcak, bitişik veriler içindir. Bu gösterim oldukça önbellek dostudur.
hız
Dolayısıyla, yukarıdaki gibi bir gösterimin kullanılması, oldukça iyi bir performans dengesi sağlayabilir. Muhtemelen değişmez veri yapılarının performans açısından en kritik kullanımları, değiştirilmemiş parçaları kopyalarken sığ veri parçalarını değiştirmenin ve işlem sırasında benzersiz kılmanın bu niteliğini üstlenecektir. Aynı zamanda sığ kopyalanmış parçalara çok iş parçacıklı bir bağlamda (muhtemelen bazı atomik referans sayımı devam ederken) güvenli bir şekilde referans vermek için bazı atomik işlem yükü anlamına gelir.
Yine de, bu tıknaz veri parçaları yeterince kaba bir seviyede temsil edildiği sürece, bu ek yükün birçoğu azalır ve muhtemelen önemsiz hale gelirken, bize hala dış tarafı olmayan saf bir biçimde kodlama ve daha fazla işlevin güvenliğini ve çoklu işleyişini sağlar Etkileri.
Yeni ve Eski Verileri Saklamak
Değişmezliği, performans açısından potansiyel olarak en yararlı olarak gördüğümde (pratik anlamda), hedefin yeni bir şey üretmek olduğu değişken bir bağlamda benzersiz kılmak için büyük verilerin tüm kopyalarını çıkarmaya cazip olacağımız zamandır. Dikkatli, değişmez bir tasarımla sadece küçük parçalarını ve parçalarını eşsiz kılan, hem yeni hem de eski tutmak istediğimiz bir şekilde var olan bir şey.
Örnek: Sistemi Geri Al
Bunun bir örneği geri al sistemidir. Bir veri yapısının küçük bir kısmını değiştirebiliriz ve hem yapabileceğimiz orijinal formu hem de yeni formu korumak isteriz. Veri yapısının sadece küçük, değiştirilmiş bölümlerini benzersiz kılan bu tür değişmez tasarım sayesinde, eski verilerin bir kopyasını bir geri alma girişinde depolarken, yalnızca eklenmiş benzersiz bölümler verilerinin bellek maliyetini ödeyebiliriz. Bu, çok etkili bir verimlilik dengesi (bir geri alma sisteminin uygulanmasını bir parça kek yapmak) ve performans sağlar.
Üst Seviye Arayüzler
Ancak yukarıdaki durumla ilgili garip bir şey ortaya çıkıyor. Yerel bir tür işlev bağlamında, değişken veriler genellikle değiştirilmesi en kolay ve en basittir. Ne de olsa, bir diziyi değiştirmenin en kolay yolu çoğu zaman sadece onu geçip aynı anda bir elemanı değiştirmektir. Bir diziyi dönüştürmeyi seçecek çok sayıda yüksek seviye algoritmaya sahip olsaydık ve değiştirilen tüm parçalar kopyalanırken tüm bu tıknaz sığ kopyaların yapılmasını sağlamak için uygun olanı seçmek zorunda kalırsak, düşünsel ek yükü yükseltebiliriz. benzersiz yaptı.
Muhtemelen bu durumlarda en kolay yol, değiştirilemez tamponları yerel olarak, yeni bir değişmez kopya almak için veri yapısında atomik değişiklikler yapan bir fonksiyon bağlamında (genellikle bizi gezdirmezler) kullanmaktır. bu "geçici" ") ...
... veya basitçe daha yüksek ve daha yüksek seviyeli dönüşüm fonksiyonlarını veri üzerinde modelleyebiliriz ki böylelikle değişken bir tamponu değiştirme ve değişken mantık içermeyen bir yapıya dönüştürme işlemini gizleyebiliriz. Her durumda, bu henüz geniş kapsamlı bir alan değildir ve bu veri yapılarının nasıl dönüştürüleceğine yönelik anlamlı arayüzler bulmak için daha değişken tasarımları daha fazla kucaklarsak işimizi durdururuz.
Veri Yapıları
Burada ortaya çıkan bir başka şey, performans açısından kritik bir bağlamda kullanılan değişmezliğin, muhtemelen veri yapılarının, boyutların çok küçük olmadığı ve çok büyük olmadığı yerlerde, topaklı verilere parçalanmasını isteyeceğidir.
Bağlantılı listeler, buna uyum sağlamak için biraz değişiklik yapmak ve denetimsiz listelere dönüştürmek isteyebilir. Büyük, bitişik diziler, rastgele erişim için modulo indeksleme ile bitişik parçalara dönüşen bir dizi göstergeye dönüşebilir.
Potansiyel olarak veri yapılarına bakış biçimimizi ilginç bir şekilde değiştirirken, bu veri yapılarının değiştirme işlevlerini, bazı bitleri sığ kopyalama ve diğer bitleri burada benzersiz hale getirme gibi ekstra karmaşıklığı gizlemek için daha hantal bir doğaya benzetmeye zorluyor.
Verim
Her neyse, bu konuyla ilgili küçük alt düzey görüşüm. Teorik olarak, değişmezliğin çok büyükten küçüğe doğru değişen bir maliyeti olabilir. Ancak çok teorik bir yaklaşım, uygulamaların her zaman hızlı ilerlemesini sağlamaz. Onları ölçeklenebilir hale getirebilir, ancak gerçek dünya hızı genellikle daha pratik zihniyeti benimsemeyi gerektirir.
Pratik açıdan bakıldığında, performans, bakım ve güvenlik gibi özellikler, özellikle çok büyük bir kod temeli için, büyük bir bulanıklığa dönüşme eğilimindedir. Mutlak anlamda performans değişmezlikle azalırken, verimlilik ve güvenlik üzerindeki faydalarını (diş güvenliği dahil) tartışmak zor. Bunlara yapılan bir artışla, genellikle geliştiricilerin kodları böcekler tarafından boğulmadan ayarlamak ve optimize etmek için daha fazla zamana sahip olması nedeniyle pratik performansta bir artış olabilir.
Dolayısıyla, bu pratik anlamda değişmez veri yapılarının , çoğu durumda, göründüğü kadar tuhaf performans göstermesine yardımcı olabileceğini düşünüyorum. İdeal bir dünya, bu ikisinin bir karışımını arayabilir: değişmez veri yapıları ve değişkenler, değişebilenler tipik olarak çok yerel bir kapsamda kullanmak için çok güvenlidir (örneğin: bir fonksiyona yerel), değişmez olanlar dış taraftan kaçınabilir düpedüz etkilenir ve bir veri yapısındaki tüm değişiklikleri, yarış koşulu riski olmadan yeni bir sürüm üreten bir atomik işleme dönüştürür.