Değişmezlik, JavaScript’teki performansı olumsuz etkiliyor mu?


88

JavaScript'te veri yapılarını değişmez olarak işleme yönelik son bir eğilim var gibi görünüyor. Örneğin, bir nesnenin tek bir özelliğini değiştirmeniz gerekirse, yeni özellikle yepyeni bir nesne oluşturmak ve eski nesneden diğer tüm özelliklerin üzerine kopyalamak ve eski nesnenin çöp toplanmasına izin vermek daha iyidir. (Bu zaten benim anlayışım.)

İlk tepkim, performans için kötü olacağa benziyor.

Ama sonra Immutable.js ve Redux.js gibi kütüphaneler benden daha zeki insanlar tarafından yazılmışlar ve performans konusunda güçlü bir endişeleri var gibi görünüyor, bu yüzden benim çöp anlamamın (ve performans etkisinin) yanlış olup olmadığını merak ediyor.

Kaçırdığım değişmezliğin performans faydaları var mı ve çok fazla çöp oluşturmanın olumsuzluklarından ağır basıyorlar mı?


8
Değişmezlik (bazen) bir performans maliyetine sahip olduğu için kısmen performans için güçlü bir endişeleri var ve bu performans maliyetini olabildiğince asgariye indirmek istiyorlar. Taklit edilebilirlik, kendi başına, yalnızca çok iş parçacıklı kod yazmayı kolaylaştıracak şekilde performans avantajlarına sahiptir.
Robert Harvey,

8
Tecrübelerime göre, performans yalnızca iki senaryo için geçerli bir sorundur - biri, bir saniyede 30 kez bir işlem yapıldığında ve ikisi de - her yürütmede etkileri arttığında (Windows XP bir kez Windows Güncelleme süresinin geçtiği bir hata buldu.) Tarihindeki her güncellemeO(pow(n, 2)) için .) Diğer çoğu kod, bir olaya anında verilen bir cevaptır; bir tıklama, API isteği veya benzeri ve yürütme süresi sabit olduğu sürece, herhangi bir sayıda nesnenin temizlenmesi pek de önemli değildir.
Katana314,

4
Ayrıca, değişken veri yapılarının etkili uygulamaları olduğunu düşünün. Belki bunlar değişebilenler kadar verimli değillerdir, ancak naif bir uygulamadan hala daha verimlidirler. Bkz. Örneğin Chris Okasaki
Giorgio

1
@ Katana314: Benim için 30+ kez hala performans hakkında endişe haklı çıkarmak için yeterli olmazdı. Node.js'ye yazdığım küçük bir CPU emülatörünü taşıdım ve node sanal CPU'yu 20MHz'de çalıştırdı (saniyede 20 milyon kez). Bu yüzden sadece saniyede 1000+ kez bir şey yaparsam performans hakkında endişelenirdim (o zaman bile, saniyede 1000000 işlem yapana kadar gerçekten endişelenmem, çünkü bir kerede 10'dan fazlasını rahatça yapabileceğimi biliyorum) .
Slebetman

2
@RobertHarvey "İmkansızlık, tek başına, çok iş parçacıklı kod yazmayı kolaylaştıracak şekilde performans avantajlarına sahiptir." Bu tamamen doğru değil, değişmezlik, gerçek sonuçları olmayan çok yaygın paylaşımlara izin veriyor. Değişken bir ortamda çok güvensiz. Bu gibi düşünüyor verir O(1)dizi dilimleme ve O(log n)hala serbestçe eskisini kullanmak mümkün olurken bir ikili ağaca ekleme ve başka bir örnek olduğu tailstüm listenin kuyrukları aldığı tails [1, 2] = [[1, 2], [2], []]tek sürer O(n)zaman ve mekan, ama O(n^2)saymak elemanda
noktalı virgül

Yanıtlar:


59

Örneğin, bir nesnenin tek bir özelliğini değiştirmeniz gerekirse, yeni özellikle yepyeni bir nesne oluşturmak ve eski nesneden diğer tüm özelliklerin üzerine kopyalamak ve eski nesnenin çöp toplanmasına izin vermek daha iyidir.

Değişmezlik olmadan, bir nesneyi farklı kapsamlar arasında geçirmeniz gerekebilir ve nesnenin ne zaman ve ne zaman değiştirileceğini önceden bilmiyorsunuz. İstenmeyen yan etkilerden kaçınmak için, "sadece durumunda" nesnesinin tam bir kopyasını oluşturmaya başlarsınız ve bu kopyanın etrafından geçersiniz, hiçbir özelliğin değiştirilmemesi gerekse bile. Bu davanızda olduğundan çok daha fazla çöp bırakacak.

Bunun gösterdiği şey - doğru varsayım senaryosunu yaratırsanız, özellikle performans söz konusu olduğunda her şeyi kanıtlayabilirsiniz. Ancak benim örneğim, göründüğü kadar varsayımsal değil. Geçen ay tam da bu problemi çözdüğümüz bir program üzerinde çalıştım, çünkü başlangıçta değişmez bir veri yapısı kullanmaya karar verdik ve daha sonra yeniden denemek için tereddüt ettim çünkü uğraşmaya değmezdi.

Yani bunun gibi eski bir SO postasındaki davalara baktığınızda, sorularınızın cevabı muhtemelen açık bir şekilde ortaya çıkıyor - bu duruma bağlı . Bazı durumlarda değişmezlik performansa zarar verebilir, çünkü bunun tersi geçerli olabilir, birçok durumda uygulamanızın ne kadar akıllı olduğuna bağlı olarak değişebilir ve daha da fazlası için bu fark önemsiz olabilir.

Son bir not: karşılaşabileceğiniz gerçek bir dünya problemi, bazı temel veri yapıları için değişmezlik için erken veya erken karar vermeniz gerektiğidir. Sonra bunun üzerine çok fazla kod oluşturuyorsunuz ve birkaç hafta veya ay sonra kararın iyi mi yoksa kötü mü olduğunu göreceksiniz.

Bu durum için benim kişisel kurallarım:

  • İlkel veya diğer değişken türlere bağlı olarak yalnızca birkaç özniteliğe sahip bir veri yapısı tasarlarsanız, önce değişmezliği deneyin.
  • Büyük (veya tanımsız) boyutlu dizilerin, rasgele erişimin ve değişen içeriklerin dahil olduğu bir veri türü tasarlamak istiyorsanız, değişkenliği kullanın.

Bu iki uç nokta arasındaki durumlar için kararınızı kullanın. Fakat YMMV.


8
That will leave a lot more garbage than in your case.ve sorunları daha da kötüleştirmek için çalışma zamanınız muhtemelen anlamsız kopyalamayı tespit edemez ve bu nedenle (hiç kimsenin kullanmadığı süresi dolmuş değişmez bir nesnenin aksine) koleksiyon için uygun olmaz.
Jacob Raihle,

37

Her şeyden önce, değişmez veri yapılarının karakterizasyonu kesin değildir. Genel olarak, bir veri yapısının çoğu kopyalanmaz, ancak paylaşılır ve yalnızca değiştirilen kısımlar kopyalanır. Buna kalıcı bir veri yapısı denir . Çoğu uygulama, çoğu zaman kalıcı veri yapılarından faydalanabilir. Performans, işlevsel programcıların genellikle ihmal edebileceğini düşündüğü değişken veri yapılarına yeterince yakın.

İkincisi, birçok insanın tipik zorunluluk programlarındaki nesnelerin tipik yaşam süreleri hakkında oldukça yanlış bir fikre sahip olduğunu buldum. Belki de bu, bellek tarafından yönetilen dillerin popülerliğinden kaynaklanmaktadır. Bazen oturun ve gerçekten uzun ömürlü veri yapılarına kıyasla ne kadar geçici nesne ve savunma kopyası oluşturduğunuzu görün. Bence o oranda şaşırırsın.

İnsanlara işlevsel programlama sınıflarında bir algoritmanın ne kadar çöp oluşturduğunu öğrettiğim konusunda açıklamalar yaptım, ardından aynı algoritmanın tipik zorunlu versiyonunu da aynı şekilde yaratıyorum. Sadece bazı nedenlerden dolayı insanlar bunu artık farketmiyor.

Değişkenleri paylaşmaya ve cesaretlendirerek değişkenleri yaratma konusunda geçerli bir değer elde edene kadar, değişmezlik, daha temiz kodlama uygulamalarını ve daha uzun ömürlü veri yapılarını teşvik etme eğilimindedir. Bu genellikle algoritmanıza bağlı olarak daha düşük seviyede çöp olmadığında karşılaştırılabilirliğe yol açar.


8
“... o zaman ben de aynı algoritmanın tipik zorunlu versiyonunu aynı derecede yaratıyorum.” Bu. Ayrıca, bu stille yeni olan ve özellikle de genel olarak işlevsel stille yeni olan insanlar, başlangıçta optimal olmayan fonksiyonel uygulamalar üretebilirler.
15'de

1
"değişkenleri oluşturma cesaretini kırma" Bu, yalnızca varsayılan davranışın atama / zımni yapı üzerine kopyalandığı diller için geçerli değil mi? JavaScript'te bir değişken sadece bir tanımlayıcıdır; bu başlı başına bir nesne değil. Hala bir yerlerde yer kaplıyor, ancak bu ihmal edilebiliyor (özellikle JavaScript uygulamalarının çoğunda, bildiğim kadarıyla, hala işlev çağrıları için bir yığın kullanıyorsunuz, yani çoğu zaman yinelemenin tekrarı olmadıkça, çoğu için aynı yığın alanını yeniden kullanacaksınız) geçici değişkenler). Taklit edilebilirliğin bu yönüyle bir ilişkisi yoktur.
JAB

33

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 objectsve stringsbunun 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).

görüntü tanımını buraya girin

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.

görüntü tanımını buraya girin

... 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).

görüntü tanımını buraya girin

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. :

görüntü tanımını buraya girin

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, Ldiyagramı çizerken benzersiz olmamamız gerekmediğinin farkında değildim .

Mavi, sığ kopyalanmış verileri gösterir.

görüntü tanımını buraya girin

... 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:

görüntü tanımını buraya girin

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;

görüntü tanımını buraya girin

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.


11

ImmutableJS aslında oldukça verimlidir. Bir örnek alırsak:

var x = {
    Foo: 1,
    Bar: { Baz: 2 }
    Qux: { AnotherVal: 3 }
}

Yukarıdaki nesne değişmez hale getirilirse, o zaman elde edeceğiniz 'Baz' özelliğinin değerini değiştirirsiniz:

var y = x.setIn('/Bar/Baz', 3);
y !== x; // Different object instance
y.Bar !== x.Bar // As the Baz property was changed, the Bar object is a diff instance
y.Qux === y.Qux // Qux is the same object instance

Bu, sadece kök yolundaki nesnelere değer türlerini kopyalamanız gereken derin nesne modelleri için gerçekten harika performans geliştirmeleri yaratır. Nesne modeli ne kadar büyükse ve yaptığınız değişiklikler ne kadar küçükse, değişmez veri yapısının belleği ve CPU performansı o kadar çok nesne paylaşmaya başlarsa o kadar iyidir.

Diğer cevapların söylediği gibi, bunu aynı garantileri sağlamaya çalışmakla çelişirseniz x, onu manipüle edebilecek bir işleve getirmeden önce defansal olarak kopyalayın , ardından performans önemli ölçüde daha iyidir.


4

Düz bir satırda, değişmez kod, yavaş olan nesne oluşturma ek yüküne sahiptir. Bununla birlikte, değişken kodun verimli bir şekilde yönetilmesinin çok zorlaştığı birçok durum vardır (bir çok savunma kopyalamasıyla sonuçlanır, bu da pahalıdır) ve bir nesneyi kopyalamanın maliyetini azaltmak için birçok akıllı strateji vardır. , diğerleri tarafından belirtildiği gibi.

Sayaç gibi bir nesneniz varsa ve saniyede birçok kez artırılırsa, bu sayacın değişmez olması performans cezasına değmeyebilir. Uygulamanızın birçok farklı bölümü tarafından okunan bir nesneniz varsa ve bunların her biri nesnenin biraz farklı bir klonuna sahip olmak istiyorsa, bunu kullanarak iyi bir performans göstererek çok daha kolay bir zaman ayarlaması yapabilirsiniz. değişmez nesne uygulaması.


4

Bu soruyu eklemek için (zaten mükemmel bir şekilde cevaplandırılmış):

Kısa cevap evet ; performansa zarar verir, çünkü var olanları değiştirmek yerine sadece nesneyi yaratırsınız, bu da daha fazla nesne yaratma ek yükü oluşturur.


Ancak, uzun cevap gerçekten değil .

Gerçek bir çalışma zamanı bakış açısından, JavaScript'te zaten oldukça fazla sayıda çalışma zamanı nesnesi oluşturdunuz - işlevler ve hazır bilgi öğeleri JavaScript'te her yerdedir ve hiç kimse bunları kullanma hakkında iki kez düşünmez. Nesne yaratmanın aslında oldukça ucuz olduğunu savunuyorum, ancak bunun için alıntı yapmadığım için bağımsız bir argüman olarak kullanmayacağım.

Benim için en büyük 'performans' artışı çalışma zamanı performansında değil geliştirici performansında. Real World (tm) uygulamaları üzerinde çalışırken öğrendiğim ilk şeylerden biri, değişkenliğin gerçekten tehlikeli ve kafa karıştırıcı olduğu. Lanet olası uygulamanın diğer tarafından bir mutasyon olduğu ortaya çıktığında, belirsiz bir hataya neden olan şeyleri çözmeye çalışırken, yürütmenin bir parçasını (eşzamanlılık türünü değil) takip ederek birkaç saat kaybettim!

Değişmezliği kullanmak işlerin nedenini çok daha kolaylaştırır. Sen X nesne olduğunu hemen bilmek mümkün olacaktır değil ömrü boyunca değişecek ve değiştirmek için tek yolu onu klonlamak etmektir. Buna, özellikle takım ortamlarında, değişkenliğin getirebileceği herhangi bir mikro-optimizasyondan çok daha fazla değer veriyorum.

Yukarıda da belirtildiği gibi istisnalar, en önemlisi veri yapıları vardır. Nadiren, oluşturulduktan sonra bir haritayı değiştirmek istediğim bir senaryoya rastlarım (kuşkusuz, ES6 haritaları yerine sahte nesne-edebi haritalar hakkında konuşuyorum). Daha büyük veri yapılarıyla uğraşırken, değişkenlik işe yarayabilir . JavaScript'teki her nesnenin bir değer yerine referans olarak iletildiğini unutmayın.


Bununla birlikte, yukarıda belirtilen noktalardan biri GC ve kopyaların tespit edilememesi. Bu meşru bir kaygı, ama bence sadece hafıza kaygı olduğunda kaygılanır ve kendinizi bir köşeye kodlamanın daha kolay yolları vardır - örneğin, kapanışlardaki dairesel referanslar.


Sonuçta, çok az (varsa) değişken bölüme sahip olan değişken bir kod tabanına sahip olmayı ve her yerde değişkenliğe sahip olmasından biraz daha az performans göstermeyi tercih ederim . Değişmezlik, bir nedenden ötürü performans için bir endişe haline gelirse, her zaman daha sonra optimize edebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.