Eşzamanlılık olmadığında değişmezlik çok değerli midir?


53

İplik emniyetinin her zaman / sıklıkla değişmez türler ve özellikle koleksiyonlar kullanmanın ana yararı olarak bahsedildiği anlaşılmaktadır.

Bir yöntemin bir dize sözlüğünü (C # ile değiştirilemez) değiştirmeyeceğinden emin olmak istediğim bir durum var. İşleri mümkün olduğunca sınırlandırmak istiyorum.

Ancak yeni bir pakete (Microsoft Immutable Collections) bağımlılık eklemenin buna değip değmeyeceğinden emin değilim. Performans da büyük bir sorun değil.

Bu yüzden benim sorum, sabit performans gereklerinin olmadığı ve iş parçacığı güvenliği sorunlarının olmadığı durumlarda sabit koleksiyonların şiddetle tavsiye edilip edilmediğidir ? Değer örneğinin (benim örneğimde olduğu gibi) aynı zamanda bir gereklilik olabileceğini ya da olmayabileceğini düşünün.


1
Eşzamanlı modifikasyonun, iş parçacığı anlamına gelmesi gerekmez. ConcurrentModificationExceptionGenelde aynı ipliğin koleksiyonunu aynı ipliğin gövdesinde, aynı ipliğin gövdesinde mutasyona uğratan aynı ipliğin neden olduğu aptly ismine bakın foreach.

1
Demek istediğim yanlış değilsin ama bu OP'nin istediğinden farklı. Bu istisna atılır, çünkü numaralandırma sırasında değişiklik yapılmasına izin verilmez. Bir ConcurrentDictionary kullanmak, örneğin, hala bu hatadır.
edthethird

13
Belki de kendinize zıt bir soru sormalısınız: değişkenlik ne zaman değerlidir?
Giorgio

2
Java'da değişkenlik etkilenirse hashCode()veya equals(Object)sonuç değişirse, kullanım sırasında hatalara neden olabilir Collections(örneğin, bir HashSetnesnede bir "kovada" saklanır ve mutasyondan sonra başka birine gitmesi gerekir).
SJuan76

2
@ DavorŽdralo Üst düzey dillerin soyutlamaları devam ettiği sürece, yaygın değişkenlik oldukça evcildir. Bu, "geçici değerler" yaratmanın ve sessizce atmanın en yaygın soyutlamasının (C'de bile mevcut) doğal bir uzantısıdır. Belki bir CPU kullanmanın verimsiz bir yol olduğunu söylemek istersiniz, ancak bu argümanın da kusurları var: Mutajenlik mutlu ama dinamik diller genellikle değişmez-ama statik dillerden daha kötü performans gösteriyor, çünkü kısmen zeki (ama oldukça basit) değişken verileri hokkabazlık programları optimize etmek için püf noktaları: Doğrusal türleri, ormansızlaşma, vb

Yanıtlar:


101

Immutability, daha sonra kodu okurken zihinsel olarak izlemeniz gereken bilgi miktarını basitleştirir . Değişken değişkenler ve özellikle değişken sınıf üyeleri için, okuduğunuz belirli bir satırda hangi durumda olacaklarını bilmek çok zor, bir hata ayıklayıcı ile kodda ilerlemeden. Akılcı olmayan verilere sebep olması kolaydır - her zaman aynı olacaktır. Bunu değiştirmek istiyorsanız, yeni bir değer oluşturmanız gerekir.

Dürüst olmak gerekirse, işleri varsayılan olarak değiştirilemez hale getirmeyi tercih ediyorum ve sonra bunları olması gerektiği gibi kanıtlanabilecek şekilde değiştirmeyi tercih ediyorum , bunun performansa ihtiyacınız olup olmadığı ya da değişmezlik için mantıklı olmayan bir algoritma olması gerektiği.


23
+1 Eşzamanlılık, eşzamanlı mutasyondur, ancak zamanla yayılan mutasyon da bununla ilgili olduğu kadar zor olabilir
guillaume31

20
Bunu genişletmek için: değişken değişkene dayanan bir işlev, değişken değişkenin geçerli değeri olan ekstra gizli bir argüman alarak düşünülebilir. Değişken bir değişkeni değiştiren herhangi bir fonksiyonun da benzer şekilde ekstra bir dönüş değeri ürettiği, yani değişebilir durumun yeni değeri olduğu düşünülebilir. Bir kod parçasına bakarken, değişken duruma bağlı olup olmadığına veya değişebilir duruma bağlı olup olmadığına dair hiçbir fikriniz yoktur, bu yüzden değişiklikleri zihinsel olarak bulup izlemeniz gerekir. Bu aynı zamanda değişken durumu paylaşan herhangi iki kod parçası arasında eşleşmeyi sağlar ve eşleşme kötüdür.
Doval,

29
@Mehrdad People da onlarca yıldır mecliste büyük programları dağıtmayı başardı. Sonra birkaç on yıl C yaptık
Doval

11
@Mehrdad Bütün nesneleri kopyalamak, nesneler büyük olduğunda iyi bir seçenek değildir. Büyüklük düzeninin iyileştirme ile ilgili neden önemli olduğunu anlamıyorum. Verimlilikte% 20'lik bir iyileşmeyi (not: keyfi sayı) üç basamaklı bir gelişme olmadığı için kısaltır mısınız? Taklit edilebilirlik akıllıca bir varsayılandır ; Eğer yapabilirsiniz ondan sokak, ancak bir neden gerek.
Doval,

9
@Giorgio Scala, ne kadar nadiren bir değeri değiştirebilmeniz gerektiğini bile anlamamı sağladı. Ne zaman o dili kullansam, her şeyi a haline getiririm valve sadece çok nadir durumlarda bir şeyi bir şeye dönüştürmem gerektiğini bulurum var. Herhangi bir dilde tanımladığım “değişkenler” in çoğu, bazı hesaplamanın sonucunu depolayan ve güncellenmesi gerekmeyen bir değere sahip.
KChaloux

22

Kodunuz niyetinizi belirtmelidir. Bir nesnenin oluşturulduktan sonra değiştirilmesini istemiyorsanız, değiştirmeyi imkansız hale getirin.

Daldırılabilirliğin birçok faydası vardır:

  • Asıl yazarın amacı daha iyi ifade edilir.

    Aşağıdaki kodda, adı değiştirmenin uygulamanın daha sonra bir yerde bir istisna oluşturmasına neden olacağını nasıl bilebilirsin?

    public class Product
    {
        public string Name { get; set; }
    
        ...
    }
    
  • Nesnenin geçersiz bir durumda görünmemesini sağlamak daha kolaydır.

    Bunu bir kurucuda ve sadece orada kontrol etmelisin. Öte yandan, nesneyi değiştiren bir grup belirleyici ve yönteminiz varsa, bu tür denetimler özellikle zor olabilir, özellikle nesnenin geçerli olması için özellikle aynı anda iki alanın değişmesi gerektiğinde.

    Örneğin, adres yoksa null veya GPS koordinatları yoksa bir nesne geçerlidir null, ancak hem adres hem de GPS koordinatları belirtilmişse geçersizdir. Hem adres hem de GPS koordinatlarının bir ayarlayıcısı varsa ya da her ikisi de değişkense bunu doğrulamak için cehennemi düşünebiliyor musunuz?

  • Eşzamanlılık.

Bu arada, senin durumunda, üçüncü parti paketlere ihtiyacın yok. .NET Framework zaten bir ReadOnlyDictionary<TKey, TValue>sınıf içeriyor .


1
+1, özellikle "Bunu bir yapıcıda ve yalnızca orada denetlemelisiniz." IMO bu çok büyük bir avantaj.
Giorgio

10
Başka bir fayda: bir nesneyi kopyalamak ücretsizdir. Sadece bir işaretçi.
Robert Grant,

1
@MainMa Cevabınız için teşekkür ederim, fakat anladığım kadarıyla ReadOnlyDictionary, başka birinin temel sözlüğünüzü değiştirmeyeceğine dair herhangi bir garanti vermez (eşzamanlılık olmasa bile, yöntemin ait olduğu orijinal sözlükteki referansı kaydetmek isteyebilirim) sonra kullanmak için). ReadOnlyDictionary bile garip bir ad alanında bildirildi: System.Collections.ObjectModel.
Den

2
@Den: Bu benim evcil hayvanlarımdan biriyle ilgili: "salt okunur" ve "değişmez" ifadesiyle eşanlamlılar hakkında insanlar. Bir nesne salt okunur bir paketleyicide kapsüllenmişse ve başka hiçbir referans bulunmuyorsa veya evrende herhangi bir yerde tutuluyorsa , nesneyi sarmalamak onu değiştiremez hale getirecek ve paketleyicinin bir referansı, durumun kapsüllenmesi için bir kısa yol olarak kullanılabilir İçerisinde nesne var. Bununla birlikte, kodun durumun böyle olup olmadığını belirleyemediği bir mekanizma yoktur. Aksine, çünkü sarıcı sarılmış nesnenin türünü gizler, değişmez bir nesneyi
sarır

2
... kodun, elde edilen sargının güvenli bir şekilde değişmez olarak kabul edilip edilemeyeceğini bilmesini imkansız hale getirecektir.
supercat

13

Değişmezliği kullanmak için tek iş parçacıklı nedenler vardır. Örneğin

A nesnesi B nesnesini içerir.

Harici kod, Nesne B'nizi sorgular ve onu döndürürsünüz.

Şimdi üç olası durumunuz var:

  1. B değişmez, sorun değil.
  2. B değişkendir, savunmacı bir kopya çıkarır ve onu geri gönderirsiniz. Performans çarpması ancak risk yok.
  3. B değişkendir, geri döndürürsün.

Üçüncü durumda, kullanıcı kodu ne yaptığınızı fark etmeyebilir ve nesnede değişiklikler yapabilir ve bu şekilde nesnenin iç verilerini değiştirerek bu olayın kontrolünü veya görünürlüğünü değiştiremezsiniz.


9

Taklit edilebilirlik, çöp toplayıcılarının uygulanmasını da büyük ölçüde kolaylaştırabilir. Gönderen GHC wiki :

[...] Veri değişmezliği bizi çok fazla geçici veri üretmeye zorlar, ancak bu çöpleri hızlı bir şekilde toplamaya da yardımcı olur. İşin püf noktası, değişmez verilerin ASLA daha genç değerleri göstermemesidir. Gerçekten de, daha eski değerler eski bir değerin yaratıldığı tarihte mevcut değildir, bu yüzden sıfırdan gösterilemez. Değerler hiçbir zaman değiştirilmediğinden, daha sonra da gösterilemez. Bu, değiştirilemez verilerin kilit özelliğidir.

Bu, çöp toplama işlemini (GC) büyük ölçüde kolaylaştırır. İstediğimiz zaman yarattığımız son değerleri tarayabilir ve aynı setten işaret edilmeyenleri serbest bırakabiliriz (elbette, canlı değer hiyerarşisinin gerçek kökleri yığında canlıdır). [...] Bu nedenle, sezgisel bir davranışa sahip: değerlerinin yüzde kaçı çöp - daha hızlı çalışıyor. [...]


5

KChaloux’un neyi çok iyi özetlediğini açıklamak ...

İdeal olarak, iki tür alanınız vardır ve bu yüzden bunları kullanan iki tür kod vardır. Her iki alan da değişkendir ve kodun değişkenliği hesaba katması gerekmez; veya alanlar değişkendir ve anlık görüntü ( int x = p.x) alan veya bu tür değişiklikleri incelikle ele alan bir kod yazmamız gerekir .

Tecrübelerime göre, çoğu kod ikisi arasına girer, iyimser koddur: ilk çağrının p.xikinci çağrı ile aynı sonuca ulaşacağını varsayarsak, serbestçe serbest bırakılabilir verilere başvurur . Ve çoğu zaman, artık doğru olmadığı ortaya çıktığı sürece, bu doğrudur. Hata.

Öyleyse, gerçekten, şu soruyu tersine çevirin: Bunu değişken hale getirme nedenlerim nelerdir ?

  • Bellek ayırma / ücretsiz azaltma?
  • Doğaya göre değişebilir mi? (örneğin, sayaç)
  • Değiştiricileri, yatay gürültüyü korur? (Const / nihai)
  • Bazı kodları kısaltır / kolaylaştırır mı? (init default, muhtemelen üzerine yaz)

Defansif kod yazıyor musun? İmkansallık size bazı kopyaları kurtaracak. İyimser kod yazıyor musun? İmkansızlık seni o garip, imkansız hatanın deliliğinden koruyacak.


3

Değişmezliğin bir başka faydası, bu değişmez nesneleri bir havuza yuvarlamanın ilk adımı olmasıdır. Sonra onları, kavramsal ve anlamsal olarak aynı şeyi temsil eden çoklu nesneler yaratmamanız için yönetebilirsiniz. İyi bir örnek Java'nın String'i olacaktır.

Dilbilimde iyi bilinen bir fenomendir, birkaç kelimenin çok görünmesi, başka bağlamlarda da ortaya çıkması mümkündür. Böylece, birden çok Stringnesne oluşturmak yerine, bir değişmez kullanabilirsiniz. Ancak bu değişmez nesnelerle ilgilenmek için bir havuz yöneticisi tutmanız gerekir.

Bu size çok fazla hafıza kazandıracaktır. Bu da okumak için ilginç bir makale: http://en.wikipedia.org/wiki/Zipf%27s_law


1

Java, C # ve diğer benzer dillerde, sınıf tipi alanlar ya nesneleri tanımlamak ya da bu nesnelerdeki değerleri ya da durumu içine almak için kullanılabilir, ancak diller bu tür kullanımlar arasında bir ayrım yapmaz. Bir sınıf nesnesinin Georgebir tür alanı olduğunu varsayalım char[] chars;. Bu alan, bir karakter dizisini aşağıdakilerden birine yerleştirebilir:

  1. Hiçbir zaman değiştirilemeyecek, değiştirilebilecek herhangi bir koda maruz kalmayacak, ancak dış referansların var olabileceği bir dizi.

  2. Dış referansların bulunmadığı ancak George'un özgürce değiştirebileceği bir dizi.

  3. George'un sahip olduğu ancak George'un şu anki durumunu temsil etmesi beklenen görünümlerin dışında var olabileceği bir dizi.

Ek olarak, değişken, bir karakter dizisini enkapsüle etmek yerine, canlı bir görünümü başka bir nesnenin sahip olduğu bir karakter dizisine kapsüllenebilir

Eğer charshalen karakter dizisini [rüzgar] kapsüller ve George istediği charskarakter dizisini [değnek] saklanması, George yapabileceği şeylerin bir numara vardır:

A. [değnek] karakterlerini içeren yeni bir dizi oluşturun charsve eskisini değil bu diziyi tanımlamak için değiştirin .

B. Bir şekilde, karakterleri daima [wand] tutacak charsve eski olandan ziyade bu diziyi tanımlayacak şekilde değiştirecek olan önceden var olan bir karakter dizisini tanımlayın.

C tarafından tanımlanan bir dizi ikinci karakter değiştirme charsbir etmek a.

Durum 1'de, (A) ve (B) istenen sonucu elde etmenin güvenli yollarıdır. (2), (A) ve (C) 'nin güvenli olduğu durumda, ancak (B)' nin acil sorunlara yol açmayacağı, ancak George dizinin sahipliğini üstleneceği varsaydığından, irade dizisini değiştirebilir]. (3) durumunda, (A) ve (B) seçimleri dış görünümleri bozar ve bu nedenle sadece seçim (C) doğrudur. Bu nedenle, alan tarafından kapsüllenen karakter dizisinin nasıl değiştirileceğini bilmek, hangi anlamsal alanın olduğunu bilmeyi gerektirir.

char[]Potansiyel olarak değişebilen bir karakter dizisini kaplayan bir tür alanını kullanmak yerine , kod Stringdeğişmeyen bir karakter dizisini kaplayan bir tür kullandıysa , yukarıdaki sorunların tümü ortadan kalkar. StringTürün tüm alanları, hiçbir zaman değişmeyecek olan paylaşılabilir bir nesneyi kullanarak bir dizi karakteri kaplar. Sonuç olarak, eğer bir tür alanString"rüzgar" ı kapsüller, onu "değnek" içine almanın tek yolu, onu "değnek" tutan farklı nesneyi tanımlamaktır. Kodun nesneye tek referansı tuttuğu durumlarda, nesneyi mutasyona geçirmek, yeni bir tane oluşturmaktan daha etkili olabilir, ancak herhangi bir sınıf değişebilir olduğunda, değeri içine alabileceği farklı yollar arasında ayrım yapmak gerekir. Şahsen, bunun için Apps Hungarian'ın kullanılması gerektiğini düşünüyorum ( char[]bu tür kullanımların aynı olduğunu düşündüğü halde - tam olarak Apps Hungarian'ın parladığı durumun türü gibi), bunun dört kullanımının anlamsal olarak farklı türler olduğunu düşünürdüm. Bu belirsizliklerden kaçınmanın en kolay yolu, değerleri yalnızca tek yönlü kaplayan değişmez tipler tasarlamaktır.


Makul bir cevaba benziyor ancak okunması ve anlaşılması biraz zor.
Den

1

Burada bazı güzel örnekler var ama değişmezliğin bir tonda yardımcı olduğu bazı kişisel deneyimlere katılmak istedim. Benim durumumda, üst üste binen okuma ve yazmalara paralel olarak sadece kodları güvenle çalıştırabilme ve yarış koşulları hakkında endişelenmemesi umuduyla değişmez eşzamanlı bir eşzamanlı veri yapısı tasarlamaya başladım. John Carmack böyle bir fikir hakkında konuştuğu yerde yapmam için bana ilham verdi. Oldukça basit bir yapı ve bu şekilde uygulanması oldukça önemsiz:

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

Elbette birkaç tane daha zil ve ıslık çalmakla birlikte, elementleri sabit bir zamanda çıkarabilir ve geri çekilebilir delikleri geride bırakabilir ve bloklar boşalır ve belirli bir değişmez durum için potansiyel olarak serbest kalırsa geri çekilir. Ancak temelde yapıyı değiştirmek için, "geçici" bir sürümü değiştirirsiniz ve eski sürümle temas etmeyen yeni bir değişmez kopya elde etmek için üzerinde yaptığınız değişiklikleri atomik olarak taahhüt edersiniz, yeni sürüm sadece blokların yeni kopyalarını oluşturur. sığ kopyalama ve referansların diğerlerine sayılması sırasında benzersiz hale getirilmesi gerekir.

Ancak, ben bulamadık ookuyuculu amaçlar için kullanışlıdır. Ne de olsa, bir fizik sisteminin aynı anda bir fiziği aynı anda uyguladığı ve bir oyuncu dünyadaki elemanları hareket ettirmeye çalıştığı kavramsal bir problem var. Dönüştürülen verinin hangi değişmez kopyasıyla birlikte gidiyorsunuz, oynatıcının dönüştürdüğü veya fizik sisteminin dönüştürdüğü? Bu yüzden, bu basit kavramsal soruna gerçekten daha basit ve basit bir çözüm bulamadım, zekice daha kolay bir şekilde kilitlenen ve üst üste binen okumaları engelleyen değişmez veri yapılarına sahip olmaktan ve tamponun aynı bölümlerine tıkanmaktan kaçının. Bu, John Carmack'ın oyunlarında nasıl çözüleceğini bulmuş gibi göründüğü bir şey; en azından bir solucan arabası açmadan neredeyse bir çözüm görüyormuş gibi konuşuyor. Bu konuda ona kadar gelmedim. Görebildiğim tek şey, değişkenlerin etrafındaki her şeyi paralel hale getirmeye çalıştığımda sonsuz tasarım soruları. Keşke çabalarımın çoğu, attığı fikirlerle başladığından beri, bir gün beynini alarak geçirebilseydim.

Yine de, bu değişken veri yapısının diğer alanlardaki muazzam değerini buldum . Gerçekten garip olan ve rastgele erişime izin veren görüntüleri saklamak için şimdi bile kullanıyorum, daha fazla talimat gerektiriyor and(işaretçi yönlendirme katmanıyla birlikte sağa kaydırma ve bit yönünde), ancak aşağıdaki faydaları ele alacağım.

Sistemi Geri Al

Bundan faydalandığım en acil yerlerden biri geri alma sistemi idi. Sistem kodunu geri alma, bölgemdeki (Visual FX endüstrisi) en çok hataya neden olan şeylerden biriydi ve yalnızca üzerinde çalıştığım ürünlerde değil, rakip ürünlerde de (onların geri alma sistemleri de lapa lapa idi) çünkü Düzgün geri alma ve yineleme konusunda endişelenecek veri türleri (özellik sistemi, örgü veri değişiklikleri, birbiri ile değişim gibi mülk temelli olmayan gölgelendirici değişiklikleri, çocuğun ebeveyni değiştirme gibi görüntü hiyerarşisi değişiklikleri, görüntü / doku değişiklikleri, vb. vb.)

Bu nedenle, gerekli geri alma kodunun miktarı muazzamdı; çoğu zaman, geri alma sisteminin durum değişikliklerini kaydetmesi gereken sistemi uygulayan kod miktarına rakip oldu. Bu veri yapısına dayanarak, geri alma sistemini aşağı yukarı çekebildim:

on user operation:
    copy entire application state to undo entry
    perform operation

on undo/redo:
    swap application state with undo entry

Normalde, yukarıdaki kod, sahne verileriniz gigabaytları tamamen kopyalamak için kullandığında büyük ölçüde etkin olmaz. Ancak bu veri yapısı sadece değişmeyen şeyleri kopyalar ve aslında tüm uygulama durumunun değiştirilemez bir kopyasını yeterince ucuza saklar. Şimdi geri alma sistemlerini yukarıdaki kod kadar kolay bir şekilde uygulayabiliyorum ve uygulama durumundaki değişmeyen kısımları daha ucuz, daha ucuz ve daha ucuz hale getirmek için bu değişmez veri yapısını kullanmaya odaklanıyorum. Bu veri yapısını kullanmaya başladığımdan beri, tüm kişisel projelerim sadece bu basit modeli kullanan sistemleri geri alıyor.

Şimdi burada hala bazı ek yükler var. En son ölçtüğümde, uygulama durumunun hiçbirinde değişiklik yapmadan tüm uygulama durumunu sığdırmak yaklaşık 10 kilobayt idi (bu, sahne hiyerarşisinde düzenlendiğinden sahne karmaşıklığından bağımsızdır, bu nedenle kök altında hiçbir şey değişmezse, sadece kök çocuklara inmek zorunda kalmadan sığ kopyalanır). Bu, yalnızca delta depolayan bir geri alma sistemi için ihtiyaç duyulacak 0 bayttan çok uzak. Ancak işlem başına 10 kilobayt geri alma işleminde, her 100 kullanıcı işleminde sadece bir megabayt. Artı, gerekirse, gelecekte de potansiyel olarak onu daha da ezebilirim.

İstisna-Emniyet

Karmaşık bir uygulamayla istisnai güvenlik önemsiz bir mesele değildir. Bununla birlikte, uygulama durumunuz değişmez olduğunda ve yalnızca atomik değişim işlemlerini gerçekleştirmek için geçici nesneler kullanıyorsanız, o zaman kendiliğinden istisnai güvenlidir, çünkü kodun herhangi bir kısmı atılırsa, geçici yeni bir kopyalanabilir kopya vermeden önce atılır . Böylece, her zaman karmaşık bir C ++ kod tabanında bulabilmek için bulduğum en zor şeylerden birini önemsizleştiriyor.

Çok fazla insan sık sık RAII'ye uygun kaynakları sadece C ++ 'da kullanır ve bunun istisnai güvenlik için yeterli olduğunu düşünür. Genellikle, bir işlev genellikle, kapsamı içinde yerel olanların ötesindeki durumlara yan etkilere neden olabileceğinden değildir. Genellikle, bu durumlarda kapsam korumaları ve karmaşık geri alma mantığı ile ilgilenmeye başlamanız gerekir. Bu veri yapısı, fonksiyonlar yan etkilere neden olmadığından sık sık uğraşmama gerek kalmadı. Başvurunun durumunu dönüştürmek yerine dönüştürülen uygulama durumunun değiştirilmiş kopyalarını döndürüyorlar.

Tahribatsız Düzenleme

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

Tahribatsız düzenleme, asıl kullanıcı verilerine dokunmadan işlemleri temelde katmanlamak / istiflemek / birbirine bağlamaktır (yalnızca giriş verisine dokunmadan giriş verileri ve çıkış verileri). Photoshop gibi basit bir görüntü uygulamasıyla uygulama yapmak önemsizdir ve çoğu işlem yalnızca görüntünün her pikselini dönüştürmek isteyebileceğinden bu veri yapısından çok fazla yararlanamayabilir.

Bununla birlikte, tahribatsız ağ düzenlemesi ile, örneğin birçok işlem çoğu zaman ağın sadece bir bölümünü dönüştürmek ister. Bir işlem sadece bazı köşeleri buraya taşımak isteyebilir. Bir diğeri sadece bazı çokgenleri oraya bölmek isteyebilir. Burada değişmez veri yapısı, sadece küçük bir kısmı değişmiş olarak ağın yeni bir versiyonunu döndürmek için tüm ağın tam bir kopyasını yapma zorunluluğundan kaçınmada bir ton yardımcı olur.

Yan Etkilerin En Aza İndirilmesi

Elinizdeki bu yapılar sayesinde, yan etkilerini en aza indiren ve bunun için çok büyük bir performans cezası vermeden fonksiyon yazmayı kolaylaştırır. Kendimi, bugün biraz yanıltıcı görünmese bile, yan etkilere maruz kalmadan, tüm değişken veri yapılarını değere döndüren daha fazla işlev yazarken buldum.

Örneğin, tipik olarak, bir grup pozisyonu dönüştürme eğilimi, bir matris ve bir nesne listesi kabul etmek ve bunları değişken bir şekilde dönüştürmek olabilir. Bugünlerde kendimi yeni bir nesne listesi döndürerek buluyorum.

Sisteminizde böyle bir yan etkisi olmayan daha fazla fonksiyona sahip olduğunuzda, doğruluğunu sınamanın yanı sıra doğruluğu hakkında düşünmeyi de kesinlikle kolaylaştırır.

Ucuz Kopyaların Yararları

Her neyse, bunlar değişmez veri yapılarından (veya kalıcı veri yapılarından) en fazla yararlandığım yerler. Ayrıca başlangıçta biraz abartılı oldum ve değişmez bir ağaç ve değişmez bağlı bir liste ve değişmez hash tablosu yaptım, ancak zamanla nadiren bunlar için çok fazla kullanım buldum. Ağırlıklı olarak yukarıdaki tıknaz değişmez dizi benzeri kabın en çok kullanımını buldum.

Ayrıca hala değişkenlerle çalışan bir çok kodum var (en azından düşük seviye kod için pratik bir gereklilik buluyorum), ancak asıl uygulama durumu, değişmez bir sahneden içindeki değişken bileşenlere açılan son derece değişken bir hiyerarşidir. Daha ucuz bileşenlerin bazıları hala tam olarak kopyalanmaktadır, ancak kafesler ve görüntüler gibi en pahalı olanlar, yalnızca dönüştürülmesi gereken parçaların kısmi ucuz kopyalarına izin vermek için değişmez yapıyı kullanır.


0

Zaten çok iyi cevaplar var. Bu sadece .NET'e özgü bir bilgidir. Eski .NET blog gönderilerini kazıyordum ve Microsoft Immutable Collections geliştiricilerinin bakış açısına göre faydaların güzel bir özetini buldum:

  1. Anlık görüntü semantiği, koleksiyonlarınızı alıcının asla değişmeyecek şekilde güvenebileceği şekilde paylaşmanıza olanak tanır.

  2. Çok iş parçacıklı uygulamalarda örtük iplik güvenliği (koleksiyonlara erişmek için kilit gerekmez).

  3. Bir koleksiyon türünü kabul eden veya iade eden bir sınıf üyeniz varsa ve sözleşmeye salt okunur anlambilgisi eklemek istediğinizde.

  4. Fonksiyonel programlama dostu.

  5. Orijinal koleksiyonun değişmediğinden, numaralandırma sırasında bir koleksiyonun değiştirilmesine izin verin.

  6. Kodunuzun zaten ilgilendiği bu yüzden aynı IReadOnly * arabirimlerini uygularlar, böylece geçiş kolaydır.

Birisi size bir ReadOnlyCollection, bir IReadOnlyList veya bir IEnumerable verirse, tek garanti veriyi değiştiremeyeceğinizdir - sizi toplayan kişinin değiştirmeyeceğinin garantisi yoktur. Yine de, değişmeyeceğinden biraz emin olmanız gerekir. Bu türler, içerikleri değiştiğinde sizi bilgilendirecek etkinlikler sunmazlar ve değişirlerse, muhtemelen içeriğini sıralarken farklı bir iş parçacığında meydana gelebilir mi? Bu tür bir davranış uygulamanızda veri bozulmasına ve / veya rastgele istisnalara yol açacaktır.

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.