Cevabı bilen ve / veya bununla ilgili bir fikri olan var mı?
Tuples normalde çok büyük olmayacağından, bunlar için sınıflardan çok yapıları kullanmanın daha mantıklı olacağını varsayıyorum. Ne diyorsun?
Cevabı bilen ve / veya bununla ilgili bir fikri olan var mı?
Tuples normalde çok büyük olmayacağından, bunlar için sınıflardan çok yapıları kullanmanın daha mantıklı olacağını varsayıyorum. Ne diyorsun?
Yanıtlar:
Microsoft, basitlik adına tüm demet türlerini referans türlerini yaptı.
Şahsen bunun bir hata olduğunu düşünüyorum. 4'ten fazla alan içeren diziler çok sıra dışıdır ve yine de daha tipik bir alternatifle değiştirilmelidir (F #'daki bir kayıt türü gibi), bu nedenle yalnızca küçük demetler pratik ilgi çekicidir. Kendi kıyaslamalarım, 512 bayta kadar kutulanmamış tupleların, kutulu tuplelardan daha hızlı olabileceğini gösterdi.
Bellek verimliliği bir endişe kaynağı olsa da, bence en yaygın sorun .NET çöp toplayıcısının ek yükü. .NET üzerinde ayırma ve toplama çok pahalıdır , çünkü çöp toplayıcısı çok yoğun bir şekilde optimize edilmemiştir (örneğin JVM ile karşılaştırıldığında). Ayrıca, varsayılan .NET GC (iş istasyonu) henüz paralelleştirilmemiştir. Sonuç olarak, tüm çekirdekler paylaşılan çöp toplayıcı için mücadele ettiğinden, demetleri kullanan paralel programlar durma noktasına gelir ve ölçeklenebilirliği yok eder. Bu sadece baskın endişe değil, AFAIK, bu sorunu incelerken Microsoft tarafından tamamen ihmal edildi.
Diğer bir endişe de sanal gönderimdir. Başvuru türleri alt türleri destekler ve bu nedenle, üyeleri genellikle sanal gönderim yoluyla çağrılır. Buna karşılık, değer türleri alt türleri destekleyemez, bu nedenle üye çağırma tamamen belirsizdir ve her zaman doğrudan bir işlev çağrısı olarak gerçekleştirilebilir. Sanal dağıtım, modern donanımda oldukça pahalıdır çünkü CPU, program sayacının nerede biteceğini tahmin edemez. JVM, sanal dağıtımı optimize etmek için büyük çaba gösterir, ancak .NET bunu yapmaz. Ancak .NET, değer türleri biçiminde sanal dağıtımdan bir çıkış sağlar. Dolayısıyla, tuple'ları değer türleri olarak temsil etmek, yine burada performansı önemli ölçüde artırabilir. Örneğin, aramaGetHashCode
2-tuple üzerinde bir milyon kere 0.17s alır ama onu eşdeğer bir yapıda çağırmak sadece 0.008s alır, yani değer türü referans tipinden 20 kat daha hızlıdır.
Tuple'larla ilgili bu performans sorunlarının yaygın olarak ortaya çıktığı gerçek bir durum, tupleların sözlüklerde anahtar olarak kullanılmasıdır. Aslında Stack Overflow sorusundan bir bağlantıyı izleyerek bu konuya rastladım F # algoritmamı Python'dan daha yavaş çalıştırıyor! yazarın F # programının Python'undan daha yavaş olduğu ortaya çıktı, çünkü o kutulu tuple kullanıyordu. Elle yazılmış bir struct
tür kullanarak manuel olarak kutudan çıkarmak , F # programını Python'dan birkaç kat daha hızlı ve daha hızlı hale getirir. Başlıklar değer türleri ile temsil edilse ve başlangıçta başvuru türleri değil, bu sorunlar asla ortaya çıkmazdı ...
Tuple<_,...,_>
türler mühürlenmiş olabilir, bu durumda referans türler olmasına rağmen sanal gönderime gerek kalmaz. Neden referans tip olduklarından çok neden mühürlenmediklerini merak ediyorum.
Bunun nedeni büyük olasılıkla, küçük bir bellek ayak izine sahip olacağından, yalnızca küçük demetler değer türleri olarak mantıklı olacaktır. Daha büyük kayıtlar (yani daha fazla özelliğe sahip olanlar), 16 bayttan daha büyük olacakları için gerçekte performans açısından zarar göreceklerdir.
Bazı demetlerin değer türü, diğerlerinin de referans türü olması ve geliştiricilerin hangilerinin hangileri olduğunu bilmesini sağlamak yerine, Microsoft'taki insanların hepsini referans türlerini yapmanın daha basit olduğunu düşündüm.
Ah, şüpheler doğrulandı! Lütfen Building Tuple'a bakın :
İlk büyük karar, demetleri referans veya değer türü olarak ele alıp almamaktı. Bir demetin değerlerini değiştirmek istediğiniz her an değişmez olduklarından, yeni bir tane oluşturmanız gerekir. Referans türlerse, bu, sıkı bir döngüdeki bir demetteki öğeleri değiştirirseniz çok fazla çöp oluşabileceği anlamına gelir. F # tuplelar referans türleriydi, ancak iki ve belki de üç öğe demetleri bunun yerine değer türleri olsaydı, takımdan bir performans iyileştirmesi gerçekleştirebileceklerine dair bir his vardı. Dahili kayıtlar oluşturan bazı ekipler, senaryoları çok sayıda yönetilen nesne oluşturmaya çok duyarlı olduğundan referans türleri yerine değer kullandı. Bir değer türü kullanmanın onlara daha iyi performans sağladığını buldular. Demet spesifikasyonunun ilk taslağımızda, iki, üç ve dört elemanlı demetleri değer türleri olarak tuttuk, geri kalanlar referans türlerdi. Bununla birlikte, diğer dillerden temsilcilerin katıldığı bir tasarım toplantısında, bu "bölünmüş" tasarımın, iki tür arasındaki biraz farklı anlambilim nedeniyle kafa karıştırıcı olacağına karar verildi. Davranış ve tasarımdaki tutarlılığın, potansiyel performans artışlarından daha öncelikli olduğu belirlendi. Bu girdiye dayalı olarak tasarımı değiştirdik, böylece F # ekibinden bazı boyutlardaki tuple'lar için bir değer türü kullanırken bir hızlanma yaşayıp yaşamadığını görmek için bazı performans araştırması yapmalarını istedik. F # ile yazılan derleyicisinden bu yana bunu test etmenin iyi bir yolu vardı. çeşitli senaryolarda demetler kullanan büyük bir programa iyi bir örnekti. Sonunda, F # ekibi, bazı demetler referans türleri yerine değer türleri olduğunda performans artışı elde etmediğini buldu. Bu, demet için referans türlerini kullanma kararımız konusunda bizi daha iyi hissettirdi.
.NET System.Tuple <...> türleri yapı olarak tanımlandıysa, ölçeklenebilir olmazlardı. Örneğin, uzun tamsayılardan oluşan üçlü bir demet şu anda aşağıdaki gibi ölçeklenir:
type Tuple3 = System.Tuple<int64, int64, int64>
type Tuple33 = System.Tuple<Tuple3, Tuple3, Tuple3>
sizeof<Tuple3> // Gets 4
sizeof<Tuple33> // Gets 4
Üçlü demet bir yapı olarak tanımlandıysa, sonuç aşağıdaki gibi olacaktır (uyguladığım bir test örneğine göre):
sizeof<Tuple3> // Would get 32
sizeof<Tuple33> // Would get 104
Tuplelar, F # 'da yerleşik sözdizimi desteğine sahip olduğundan ve bu dilde son derece sık kullanıldığından, "struct" tuple, F # programcılarının farkında olmadan verimsiz programlar yazma riskiyle karşı karşıya kalmasına neden olur. Çok kolay olurdu:
let t3 = 1L, 2L, 3L
let t33 = t3, t3, t3
Bana göre, "yapı" demetleri günlük programlamada önemli verimsizlikler yaratma olasılığının yüksek olmasına neden olur. Öte yandan, şu anda var olan "sınıf" demetler de @Jon tarafından belirtildiği gibi bazı verimsizliklere neden olur. Bununla birlikte, "oluşma olasılığı" çarpı "potansiyel hasar" çarpımının, yapılarda şu anda sınıflarda olduğundan çok daha yüksek olacağını düşünüyorum. Bu nedenle, mevcut uygulama daha az kötülüktür.
İdeal olarak, her ikisi de F # 'da sözdizimsel desteği olan "sınıf" demetleri ve "yapı" demetleri olacaktır!
Düzenle (2017-10-07)
Struct tuples artık aşağıdaki gibi tam olarak desteklenmektedir:
ref
veya sözde "değişmez yapılar" ın özellikle kutulandığında olmadığı gerçeğinden hoşlanmaması olabilir. Bu çok kötü .net, parametrelerin geçme kavramını hiçbir zaman bir yürütülebilir tarafından uygulanmadı const ref
, çünkü çoğu durumda gerçekten gerekli olan bu tür anlambilimdir.
Dictionary
, örneğin burada: stackoverflow.com/questions/5850243 /…
2 tuple'lar için, Common Type System'in önceki sürümlerinden KeyValuePair <TKey, TValue> kullanmaya devam edebilirsiniz. Bu bir değer türüdür.
Matt Ellis makalesine küçük bir açıklama, referans ve değer türleri arasındaki kullanım anlambilimindeki farkın, değişmezlik yürürlükte olduğunda yalnızca "küçük" olduğudur (tabii ki burada durum böyle olacaktır). Bununla birlikte, BCL tasarımında, Tuple'ın bir eşikte bir referans tipine geçmesi konusundaki kafa karışıklığını ortaya koymamak en iyisi olacağını düşünüyorum.
Bilmiyorum ama F # Tuples kullandıysanız, dilin bir parçasıdır. Bir .dll yapıp bir tür Tuple döndürdüysem, bunu yerleştirmek için bir türe sahip olmak güzel olur. Şimdi F # dilinin bir parçası olduğundan şüpheleniyorum (.Net 4) bazı ortak yapıları barındırmak için CLR'de bazı değişiklikler yapıldı F #
Gönderen http://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records
let scalarMultiply (s : float) (a, b, c) = (a * s, b * s, c * s);;
val scalarMultiply : float -> float * float * float -> float * float * float
scalarMultiply 5.0 (6.0, 10.0, 20.0);;
val it : float * float * float = (30.0, 50.0, 100.0)
ValueTuple<...>
. En referansına bakın C # tanımlama grubu tipleri