Kütüphaneleri kullanırken verimlilik sağlamak neden zor?


10

Herhangi bir küçük veritabanı işlemesi, dilin kendisinden kütüphaneler ve / veya yardımcı programlar kullanan Python / Perl / ... komut dosyaları ile kolayca ele alınabilir. Bununla birlikte, performans söz konusu olduğunda, insanlar C / C ++ / düşük seviyeli dillere ulaşma eğilimindedir. Kodu ihtiyaçlara göre uyarlama olasılığı, bu dilleri BigData için çekici kılan şeydir - bellek yönetimi, paralellik, disk erişimi ve hatta düşük düzeyli optimizasyonlar (C / C ++ düzeyinde montaj yapıları aracılığıyla).

Tabii ki bu tür faydalar bir bedel olmadan gelmeyecekti: kodu yazmak ve hatta bazen tekerleği yeniden icat etmek oldukça pahalı / yorucu olabilir. Mevcut kütüphanelerin bir sürü rağmen onlar gerektiğinde, insanlar kendileri tarafından kod yazmak için eğimlidir vermek performansı. Büyük veritabanlarını işlerken performans iddialarının kitaplıkları kullanmasını ne engeller ?

Örneğin, web sayfalarını sürekli olarak tarayan ve toplanan verileri ayrıştıran bir girişim düşünün. Her bir kayan pencere için, çıkarılan veriler üzerinde farklı veri madenciliği algoritmaları çalıştırılır. Geliştiriciler neden mevcut kütüphaneleri / çerçeveleri kullanarak tarama yapıyor (tarama, metin işleme ve veri madenciliği için olsun)? Halihazırda uygulanmış olan şeyleri kullanmak sadece tüm süreci kodlama yükünü hafifletmekle kalmaz, aynı zamanda çok zaman kazandırır.

Tek çekimde :

  • kodu kendi başına yazmanın performans garantisi olmasını sağlayan nedir?
  • neden olduğu riskli sen gerektiğinde bir çerçeveler / kütüphaneler güvenmek temin yüksek performans?

1
Soruyu kesin olarak anlatabilir misiniz? Belki aklınızdaki bazı olası cevaplar da yardımcı olabilir.
Amir Ali Akbari

@AmirAliAkbari SeanOwen bir cevap gönderdi ve sorumun özgüllüğünün eksikliğini fark ettim. Yazısına bir yorum ekledim. Lütfen, gönderimle ilgili herhangi bir iyileştirme önermekten çekinmeyin - aksi takdirde silmeyi planlıyorum.
Rubens

Yanıtlar:


4

Yeniden yazma oyununu tekrar tekrar yaptım (ve hala yapıyorum), hemen tepkim uyarlanabilirlikti .

Çerçeveler ve kütüphaneler standart görevler için büyük bir cephanelik (muhtemelen iç içe geçebilir) rutinlerine sahipken, çerçeve özellikleri genellikle (her zaman?) Kısayollara izin vermez. Aslında, çoğu çerçevenin etrafında temel bir temel işlevsellik katmanının uygulandığı bir çeşit çekirdek altyapı vardır. Daha spesifik işlevsellik, temel katmanı kullanır ve çekirdeğin etrafındaki ikinci bir katmana yerleştirilir.

Şimdi kısayollarla, çekirdeği kullanmadan doğrudan ikinci bir katman rutinden başka bir ikinci katman rutine geçmek demek. Tipik bir örnek (alan adımdan) zaman damgaları olacaktır: Bir tür zaman damgalı veri kaynağınız var. Şimdiye kadar iş sadece telden veri okumak ve çekirdeğe iletmektir, böylece diğer kodunuz onun üzerinde ziyafet çekebilir.

Artık endüstriniz varsayılan zaman damgası biçimini çok iyi bir nedenden dolayı değiştiriyor (benim durumumda unix zamanından GPS zamanına geçiyorlar). Çerçeveniz sektöre özgü değilse, zamanın temel temsilini değiştirmeye istekli olmaları pek olası değildir, bu yüzden neredeyse istediğinizi . Verilerinize her eriştiğinizde, önce endüstri zamanı biçimine dönüştürmeniz gerekir ve her değiştirilmesini istediğinizde, çekirdeğin uygun gördüğü her şeye geri dönüştürmeniz gerekir. Verileri çift dönüştürmeden doğrudan kaynaktan bir lavaboya aktarmanın bir yolu yoktur.

El yapımı çerçevelerinizin parlayacağı yer burası, sadece küçük bir değişiklik ve gerçek dünyayı yeniden modelliyorsunuz, ancak diğer (sektöre özgü olmayan) çerçevelerin artık bir performans dezavantajı olacak.

Zamanla, gerçek dünya ve model arasındaki tutarsızlık artacaktır. Bir off-the-raf çerçevesi ile yakında gibi sorular karşı karşıya olurduk: Temsil ettiğim nasıl thisbölgesi thatveya yapmak rutin nasıl X/ üretmek kabul Y.

Şimdiye kadar bu C / C ++ ile ilgili değildi. Ancak, bir nedenden dolayı çerçeveyi değiştiremezseniz, yani bir uçtan diğerine gitmek için verilerin çift dönüştürülmesine katlanmak zorunda kalırsanız, genellikle ek yükü en aza indiren bir şey kullanırsınız. Benim durumumda, bir TAI-> UTC veya UTC-> TAI dönüştürücü en iyi ham C'ye (veya bir FPGA) bırakılır. Hiçbir zerafet mümkün değil, sorunu önemsiz kılan derin bir akıllı veri yapısı yok. Bu sadece sıkıcı bir anahtar ifadesi ve neden derleyicileri tam olarak bunu optimize etmekte iyi olan bir dil kullanmıyorsunuz?


1
+1 Bu benim yazımda çok açık olmadığım için benim hatam olabilir, bu yüzden diğerleri daha önce anlamadı. Kesinlikle aradığım cevap budur. Teşekkürler.
Rubens

7

Performans bir sorun olduğunda herkesin C / C ++ 'a ulaştığını düşünmüyorum.

Düşük seviyeli kod yazmanın avantajı, daha az CPU döngüsü veya bazen daha az bellek kullanmaktır. Ancak, daha yüksek seviyeli dillerin daha düşük seviyeli dilleri arayabileceğini ve bu değerin bir kısmını elde edebileceğini unutmayın. Python ve JVM dilleri bunu yapabilir.

Örneğin, masaüstünde scikit-learn kullanan veri bilimcisi, sayı çatırtısını yapmak için zaten çok optimize edilmiş yerel rutinleri çağırıyor. Hız için yeni kod yazmanın bir anlamı yok.

Dağıtılmış "büyük veri" bağlamında, veri hareketi konusunda daha tipik bir darboğazınız vardır: ağ aktarımı ve G / Ç. Yerel kod yardımcı olmuyor. Yardımcı olan daha hızlı çalışmak için aynı kodu yazmak değil, daha akıllı kod yazmaktır.

Daha yüksek seviyeli diller, belirli bir geliştirici zamanında C / C ++ 'dan daha karmaşık dağıtılmış algoritmalar uygulamanıza izin verecektir. Ölçekte, daha iyi veri hareketine sahip daha akıllı algoritma aptal yerel kodu yenecektir.

Ayrıca, geliştirici zamanının ve hataların maliyetinin yeni donanımdan daha fazla yüklendiği de genellikle doğrudur. Üst düzey bir geliştiricinin bir yıllık süresi tam olarak 200 bin dolar olabilir; bir yıl boyunca yüzlerce sunucu hesaplama süresine değer. Çoğu durumda, daha fazla donanım atma konusunda optimizasyonu zahmete sokmak mantıklı olmayabilir.

"Hibe" ve "devre dışı bırak" ve "onayla" ile ilgili takibi anlamıyorum?


Yanlış anlaşılma için üzgünüm. Niyetim, bir uygulama üzerinde kontrol sahibi olmanın önemi ve bu kontrolün kütüphaneler tarafından nasıl gevşetildiği ile ilgili cevaplar getirmekti . Elbette onlar hakkında bir şeyler varsayabilirsiniz (insanlar normalde pthreads'leri yeniden yazmaz), ancak veriler değişirse (yük, verim, ...), performans vermek için lib kaynağına erişmeniz gerekebilir. Ve evet, mutlaka C / C ++ değil - genellikle hpc için seçilen diller olsalar da. Sorumu silebilir miyim yoksa daha spesifik bir şeye mi dönüştürmek istersiniz? Bunu geliştirmek için herhangi bir öneriyi kabul ediyorum.
Rubens

1
Hayır, güzel bir soru, isterseniz sorularınızı düzenlemelerde yorumlarınızı burada yansıtabilirsiniz.
Sean Owen

Lütfen, sorunun şimdi anlamlı olup olmadığını kontrol edin. Daha basit hale getirmek için küçük bir kasa ekledim. Soruya biraz dikkat çekmek isterseniz, lütfen düzenlemekten çekinmeyin.
Rubens

4

Bildiğimiz gibi, Dijital dünyada aynı işi yapmanın / beklenen sonuçları almanın birçok yolu var.

Koddan doğan sorumluluklar / riskler geliştiricilerin omuzlarındadır.

Bu küçük ama sanırım .NET dünyasından çok faydalı bir örnek ..

Pek çok .NET geliştiricisi, performans / işlem üzerinde kontrol elde etmek için veri serileştirmelerinde yerleşik BinaryReader - BinaryWriter'ı kullanır.

Bu BinaryWriter sınıfında yerleşik aşırı yüklü Yazma Yöntemlerinden biri olan FrameWork CSharp kaynak kodudur:

// Writes a boolean to this stream. A single byte is written to the stream
// with the value 0 representing false or the value 1 representing true.
// 
public virtual void Write(bool value) 
{
     //_buffer is a byte array which declared in ctor / init codes of the class
    _buffer = ((byte) (value? 1:0));

    //OutStream is the stream instance which BinaryWriter Writes the value(s) into it.
    OutStream.WriteByte(_buffer[0]);
}

Gördüğünüz gibi, bu yöntem _buffer değişkenine fazladan atanmadan yazılabilir:

public virtual void Write(bool value) 
{
    OutStream.WriteByte((byte) (value ? 1 : 0));
}

Atanmadan birkaç milisaniye kazanabiliriz ... Bu birkaç milisaniye "neredeyse hiçbir şey" olarak kabul edebilir, ancak ya binlerce yazma varsa (yani bir sunucu işleminde)?

Diyelim ki "az" 2 (milisaniye) ve çok-bin örnek sadece 2.000. Bu, 4 saniye daha fazla işlem süresi anlamına geliyor. 4 saniye sonra geri dönüyor ..

.NET'ten konu almaya devam edersek ve BCL - .NET Base Sınıf Kütüphanesi'nin kaynak kodlarını MSDN'den kontrol ederseniz, geliştiricinin karar vermesinden çok fazla performans kaybı olduğunu görebilirsiniz ..

BCL kaynağından herhangi bir nokta Geliştiricinin kodlarında () döngüsü için daha hızlı bir döngü uygulayabilen while () veya foreach () döngülerini kullanmaya karar vermesi normaldir.

Bu küçük kazançlar bize toplam performansı veriyor ..

Ve BinaryWriter.Write () yöntemine dönersek ..

Aslında bir _buffer uygulamasına ekstra atama bir geliştirici hatası değildir.Bu kesinlikle "güvende kalmaya" karar verir!

_Buffer'ı kullanmaya karar vermediğimizi ve ikinci yöntemi uygulamaya karar verdiğimizi varsayalım. çünkü tüm veriler herhangi bir kontrol ve kontrol mekanizması olmadan göndermeye çalıştığımız için. bağlantı kaybedildiğinde, hem sunucu hem de istemci gönderilen veri asla bilmiyorum ya da tamamlandı.

Geliştiricinin "güvende kalmaya" karar vermesi normalde performans maliyetlerinin uygulanan "güvende kal" mekanizmalarına bağlı olduğu anlamına gelir.

Ama geliştirici "risk almak, performans kazanmak" karar verirse bu da bir hata değildir .. "Riskli" kodlama hakkında bazı tartışmalar var.

Küçük bir not olarak: Ticari kütüphane geliştiricileri her zaman güvende kalmaya çalışırlar çünkü kodlarının nerede kullanılacağını bilemezler.


4

Programcılar açısından bakıldığında, çerçeveler performansı nadiren en yüksek öncelik olarak hedefler. Eğer kitaplığınız insanların en çok değer vereceği şeylerden büyük ölçüde yararlanacaksa, kullanım kolaylığı, esneklik ve güvenilirliktir.

Performans genellikle ikincil rekabetçi kütüphanelerde değerlenir. "X kütüphanesi daha iyi çünkü daha hızlı." O zaman bile, bu kütüphaneler, yaygın olarak kullanılan bir kütüphaneye en uygun çözümü takas edeceklerdir.

Herhangi bir çerçeveyi kullanarak, doğası gereği daha hızlı bir çözümün bulunma riskini alırsınız. Neredeyse her zaman daha hızlı bir çözüm olduğunu söyleyecek kadar ileri gidebilirim.

Bir şeyi kendiniz yazmak performansın garantisi değildir, ancak ne yaptığınızı biliyorsanız ve oldukça sınırlı bir gereksinim grubunuz varsa yardımcı olabilir.

Örnek olarak JSON ayrıştırma verilebilir. JSON'u yeniden doldurulabilir bir nesneye dönüştürecek çeşitli diller için yüz kütüphane var. CPU kayıtlarında her şeyi yapan bir uygulama biliyorum. Diğer tüm ayrıştırıcılardan ölçülebilir derecede daha hızlıdır, ancak aynı zamanda çok sınırlıdır ve bu sınırlama, çalıştığınız CPU'ya bağlı olarak değişecektir.

Yüksek performanslı bir ortama özgü JSON ayrıştırıcısı oluşturma görevi iyi bir fikir midir? Saygın bir kütüphaneyi 100 üzerinden 99 kez kaldıracağım. Bu ayrı bir örnekte, bir milyon yinelemeyle çarpılan birkaç ekstra CPU döngüsü, geliştirme süresini buna değecektir.

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.