Scala deyimsel kodlama stilini sadece verimsiz kod yazmak için güzel bir tuzak mı? | Netgez.com "scala deyimsel"" /> "scala deyimsel"" />
SORU
16 AĞUSTOS 2011, Salı


Scala deyimsel kodlama stilini sadece verimsiz kod yazmak için güzel bir tuzak mı?

Scala topluluğu yazma ile biraz büyük bir takıntı olduğunu hissediyorum"", "", . serin özlü >"scala deyimsel""one-liner" -mümkünse kod. Bu hemen/zorunlu/çirkin kod Java için bir karşılaştırma tarafından takip edilir.

Bu bazen kolay kod anlamak neden olurken, aynı zamanda geliÅŸtiricilerin ™'u için verimsiz kod yol açar. Ve bu Java/C yenmek kolay deÄŸil.

Bu basit sorunu göz önünde bulundurun:Tamsayılar listesi verilen en büyük elemanını sökün.Sipariş korunmuş olması gerekmez.

İşte çözüm benim sürümü (en büyük olmayabilir, ama olmayan rockstar ortalama geliştirici bunu yapardı).

def removeMaxCool(xs: List[Int]) = {
  val maxIndex = xs.indexOf(xs.max);
  xs.take(maxIndex) ::: xs.drop(maxIndex 1)
}

Scala deyimsel, özlü, ve birkaç güzel liste fonksiyonları kullanır. Ayrıca çok verimsiz. En az 3 veya 4 kere listesini erişir.

İşte bu hiç hoş, Java gibi benim çözüm. Makul bir Java geliştirici (veya Scala acemi) yazardı.

def removeMaxFast(xs: List[Int]) = {
    var res = ArrayBuffer[Int]()
    var max = xs.head
    var first = true;   
    for (x <- xs) {
        if (first) {
            first = false;
        } else {
            if (x > max) {
                res.append(max)
                max = x
            } else {
                res.append(x)
            }
        }
    }
    res.toList
}

Tamamen non-Scala deyimsel olmayan, işlevsel olmayan, kısa ve öz, ama çok verimli değil. Bu liste sadece bir kez geçer!

EÄŸer Java geliÅŸtiricilerin ™ Scala geliÅŸtiricileri ™ daha verimli kod yazmak, bu büyük bir sorun ve bu büyük engel Scala benimsenmesi için geçmek. Bu tuzaktan kurtulmanın bir yolu var mı?

Pratik öneriler "" uygulama açık tutulması ans kısa süre. verimsizlik gibi tuzaklar önlemek için arıyorum

Açıklama:Gerçek hayattan bir senaryo geliyor bu soru: karmaşık bir algoritma yazmak zorunda kaldım. İlk Scala yazdım, sonra ben" Java. tekrar yazmak için "vardı Java uygulaması iki kat daha uzun, bu çok açık değil, ama aynı zamanda iki kat daha hızlı oldu. Verimli olması için Scala kodunu tekrar muhtemelen ve scala iç verimlilik biraz daha derin bir anlayış (kapak vs vs göster, vs.) biraz zaman alacaktı

CEVAP
17 AĞUSTOS 2011, ÇARŞAMBA


Soru: bir yanlış tartışalım

EÄŸer Java geliÅŸtiricilerin ™ yazarsanız çok daha verimli 99% daha kod GeliÅŸtiriciler Scala, bu büyük Scala için cross için büyük bir engel. evlat edinme. Bu tuzaktan kurtulmanın bir yolu var mı?

Bu, hiçbir kanıt yedekleme ile kabul edilir. Eğer yanlış, gereksiz bir soru.

Aksine bir kanıt var mı? Hadi sorunun kendisi hiçbir şeyi kanıtlamaz, ama bazı şeyler net değil gösterir ... göz önünde bulundurun.

Olmayan Scala, işlevsel olmayan, olmayan özlü tamamen deyimsel ama çok etkili. Bu liste sadece bir kez geçer!

İlk cümlede dört iddialar, ilk üç doğruysa ve user unknown ile gösterilen dördüncü, yanlış! Ve yanlış neden? İkinci cümle Birleşik Devletleri aksine, listeyi bir kez daha geçer çünkü.

Kodu aşağıdaki yöntemleri çağırır:

res.append(max)
res.append(x)

ve

res.toList

Hadi append düşünün.

  1. append sırasında bir parametre alır. max x önce bazı tür bir dizi (WrappedArray aslında) içine saklanmış ve sonra da parametre olarak geçirilen anlamına gelir. Daha iyi bir yöntem = olurdu.

  2. Tamam, append çağrı temsilcilerin 17***, 16*,. Ama, ilk, ikinci hata ( = de = sadece birden fazla eleman için optimize aramalar) ensureSize çağırır. Array, Her yeniden boyutlandırma, 22 ** bütün kopyalanması gerekir anlamına gelir sabit boyutlu bir koleksiyon, bir çünkü!

Hadi bunu düşünün. Yeniden boyutlandırdığınızda, Java ilk her elemanı 0 saklayarak bellek temizler, yeni bir diziye kopyalar önceki dizinin her bir öğesi üzerinde Scala. Boyutu her zaman iki katına beri, bu günlük(n) kez, öğeleri kopyalanan sayısı oluyor her zaman artırılması ile olur.

Örneğin n = 16. Bu dört kez, elemanları sırasıyla 1, 2, 4 ve 8 kopyalama yapar. Java beri bu dizi her temizlemek için vardır, ve her öğe okunmalıdırveyazılı, her kopye bir elementin 4 dolaşımları temsil eder. , Yaklaşık 4 (n - 1) * 4, ya da, hepimiz ekleyerek tam listesini dolaşımları. Eğer okuma ve yazma tek bir geçiş olarak sayarsak, insanlar genellikle yanlışlıkla inanıyorum, hala üç dolaşımları.

Başlangıç boyutu bir unsur atarak olacağız yana, eksi bir okuma olacağını listesine eşit ArrayBuffer başlatarak bu konuda geliştirmek. Bu boyut için, geçiş için listeyi bir kez olsa gerek.

Şimdi toList düşünün. Basitçe söylemek gerekirse, tüm listeyi yeni bir liste oluşturmak için erişir.

Yani, algoritma, 3 1 geçişi veya yeniden boyutlandırma, ve toList 1 ek geçişi için 4 dolaşımları var. 4 ya da 5 dolaşımları.

Özgün algoritması take, drop ::: elemanları değişken sayıda traverse çünkü analiz etmek biraz zor. Hepsini bir Araya ekleme, ancak, 3 dolaşımları denk geliyor. splitAt kullanıldıysa, 2 dolaşımları indirgenmiş olur. Tam verim alabilmek için 2 tane daha dolaşımları ile, 5 dolaşımları işlevsel olmayan, olmayan özlü algoritma aynı numara...!

Bakalım gelişmeler göz önünde bulundurun.

Eğer kullanıyorsa zorunlu algoritması, ListBuffer =, sonra tüm yöntemleri tek bir geçiş için azaltır, sabit zaman.

Fonksiyonel algoritması olarak yazılmış olabilir

val max = xs.max
val (before, _ :: after) = xs span (max !=)
before ::: after

Üç dolaşımları kötü bir duruma düşürür. Tabii ki, başka alternatifler, özyineleme dayalı sergilenmektedir veya kat bir geçişi içinde çözmek.

Ve, en ilginç, algoritmaları O(n) ve hemen ortaya çıkan bir tek bunlar (yanlışlıkla) en kötü karmaşıklık tüm ordu (dizi kopyalama nedeniyle). Diğer taraftanönbellekbu zorunlu bir özellikleri de verilerin bellekte bitişik olduğu için daha hızlı olun. Bu, ancak, büyük-Oh ya da işlevsel vs şart da ilgisi yoktur, ve sadece seçilen veri yapıları meselesidir.

Yani, eğer biz gerçekten gitmek sorun kıyaslama, analiz sonuçları dikkate alınarak performans yöntemleri ve doğru yollardan geçilir, o zaman biz bulmak hızlı yolu bunu yapmak için bir zorunluluk şekilde daha işlevsel bir şekilde.

Ama tüm bu çaba sadece yanlış olduğunu ortalama programcı Java kodunu soruyu bir örnek ise daha hızlı ortalama Scala programcı kod daha gelecek ... söylemekten çok farklıdır. Ve soruyu bile indirim, sorunun temel öncül doğru olduğunu gösterecek hiçbir kanıt gördük.

EDÄ°T

İlk olarak, ifade edemedim galiba çünkü benim amacım tekrar ifade edelim. Benim ortalaması Java programcı yazdığı kodu daha etkili gibi görünebilir ama aslında değildir. Ya da, başka bir deyişle, geleneksel Java tarzı sadece zor işleri performans -- kazanç, Java ve Scala olmak istemiyor.

Bir sonraki gösterge ve sonuçları da, hemen hemen tüm önerilen çözümleri de dahil olmak üzere var. Bu konuda iki ilginç nokta:

  1. Liste boyutuna bağlı olarak, nesnelerin oluşturma listesi birden çok dolaşımları daha büyük bir etkisi olabilir. Adrian tarafından özgün fonksiyonel kod listeleri ile kalıcı veri yapıları olduğu gerçeğini yararlanırkopyalama değilen fazla eleman Tamam unsurları. Eğer Vector yerine kullanılan, sol ve sağ her iki taraf da daha iyi performans yol açabilir çoğunlukla değişmeden olur.

  2. Kullanıcı bilinmeyen ve faydacı benzer özyinelemeli çözüm olsa bile, faydacı bir şekilde daha hızlı. Bunun nedeni, desen eşleştirme çekiniyor. Desen eşleştirme çok yavaş olabilir.

Referans kodu ** 36 ve sonuçları here.

Bunu PaylaÅŸ:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VÄ°DEO

Rastgele Yazarlar

  • CMTelly

    CMTelly

    2 Mayıs 2007
  • cosmicrocketman

    cosmicrocket

    17 NÄ°SAN 2006
  • edwin maldonado

    edwin maldon

    28 Mart 2009