Nesne yönelimi algoritma performansını gerçekten etkiliyor mu?


14

Nesne yönelimi birçok algoritmanın uygulanmasında bana çok yardımcı oldu. Ancak, nesne yönelimli diller bazen "basit" yaklaşımda size yol gösterir ve bu yaklaşımın her zaman iyi bir şey olup olmadığından şüphe ediyorum.

OO, algoritmaları hızlı ve kolay bir şekilde kodlamak için gerçekten yararlıdır. Ancak bu OOP, performansa dayalı yazılım için bir dezavantaj olabilir mi, yani program ne kadar hızlı çalışır?

Örneğin, grafik düğümlerin bir veri yapısında depolanması ilk etapta "basit" gibi görünür, ancak Düğüm nesneleri çok sayıda öznitelik ve yöntem içeriyorsa, bu yavaş bir algoritmaya yol açabilir mi?

Başka bir deyişle, birçok farklı nesne arasında birçok referans veya birçok sınıftan birçok yöntem kullanılması "ağır" bir uygulama ile sonuçlanabilir mi?


1
Oldukça garip bir soru. OOP'nin bir mimari düzeyde nasıl yardımcı olduğunu anlayabiliyorum. Ancak, bir düzeyde algoritma uygulaması normalde OOP'un temsil ettiği her şeye çok yabancı olan soyutlamalar üzerine inşa edilir. Bu nedenle, OOP algoritma uygulamalarınız için performans en büyük sorun değildir. Performansa gelince, OOP ile en büyük darboğaz normalde sanal çağrılarla ilgilidir.
SK-logic

@ SK-logic> nesne yönelimi, bellek ayırma tarafında daha önemli bir iş yükü anlamına gelen işaretçi ile everithing'i manipüle etme eğilimindedir ve lokalize olmayan veriler CPU önbelleğinde bulunma eğilimindedir ve son olarak, en az değil, çok fazla dolaylı ima eder CPU boru hattı için ölümcül olan dallanma (sanal fonksiyonlar). OO iyi bir şeydir, ancak bazı durumlarda kesinlikle bir performans maliyeti olabilir.
deadalnix

Grafiğinizdeki düğümlerin yüz niteliği varsa, gerçek uygulama için kullanılan paradigmadan bağımsız olarak bunları saklamak için yer gerekir ve genel olarak herhangi bir paradigmanın nasıl bir kenarı olduğunu görmüyorum. @Deadalnix: Belli optimizasyonları zorlaştırdığı için sabit faktörler belki daha kötü olabilir. Ama daha sert , imkansız olmadığını söylüyorum - örneğin, PyPy sıkı döngülerdeki nesneleri kaldırabilir ve JVM'ler sonsuza kadar sanal işlev çağrılarını satır içine alıyor.

Python, prototip algoritmaları için iyidir ve yine de tipik bir algoritmayı uygularken bir sınıfa ihtiyacınız yoktur.
İş

1
+1 Nesne yönelimini algoritmalarla ilişkilendirmek için, bu günlerde hem yazılım endüstrisinde hem de akademide gözden kaçan bir şey ...
umlcat

Yanıtlar:


17

Nesne yönlendirme, kapsülleme nedeniyle belirli algoritmik optimizasyonları engelleyebilir. İki algoritma birlikte iyi çalışabilir, ancak OO arabirimlerinin arkasında gizlenmişlerse, sinerjilerini kullanma olasılığı kaybedilir.

Sayısal kütüphanelere bakın. Birçoğu (sadece 60'larda veya 70'lerde yazılmış olanlar değil) OOP değildir. Bunun bir nedeni var - sayısal algoritmalar modules, arayüzleri ve kapsülleme ile OO hiyerarşilerinden daha iyi bir dizi ayrıştırılmış olarak çalışır.


2
Bunun temel nedeni, yalnızca C ++ 'nın OO versiyonunu verimli hale getirmek için ifade şablonlarını kullanmasıdır.
DeadMG

5
Modern C ++ kitaplıklarına (STL, Boost) bakın - onlar da OOP değildir. Ve sadece performans yüzünden değil. Algoritmalar normalde bir OOP tarzında iyi temsil edilemez. Genel programlama gibi şeyler düşük seviyeli algoritmalar için çok daha uygundur.
SK-logic

3
Ho-Ho ne? Sanırım quant_dev ve SK-logic'ten farklı bir gezegenden geliyorum. Hayır, farklı bir evren. Farklı fizik yasaları ve her şeyle.
Mike Nakis

5
@MikeNakis: bakış açısı farkı (1) belirli bir hesaplama kodunun OOP'tan insan tarafından okunabilirlik açısından fayda sağlayıp sağlayamayacağıdır (hangi sayısal tarifler yoktur); OOP sınıf tasarım olup (2) hizalar uygun veri yapısı ve algoritma ile (cevabım bakınız); ve (3) her bir aktarım katmanının yeterli "değer" sağlayıp sağlamadığı (fonksiyon çağrısı başına yapılan iş veya katman başına kavramsal netlik açısından) ek yükü haklı çıkarır (dolaylı, fonksiyon çağrısı, katmanlar veya veri kopyalama nedeniyle). (4) Son olarak, derleyici / JIT / optimizer'ın karmaşıklığı sınırlayıcı faktördür.
rwong

2
@MikeNakis, ne demek istiyorsun? Sizce STL bir OOP kütüphanesi mi? Jenerik programlama zaten OOP ile iyi gitmiyor. Ve OOP'un çok dar bir çerçeve olduğunu, sadece çok az pratik görev için uygun olduğunu, başka bir şey için yabancı olduğunu söylemeye gerek yok.
SK-logic

9

Performansı ne belirler?

Temel bilgiler: veri yapıları, algoritmalar, bilgisayar mimarisi, donanım. Artı ek yük.

Bir OOP programı, CS teorisi tarafından en uygun görülen veri yapıları ve algoritmaların seçimi ile tam olarak hizalanacak şekilde tasarlanabilir . Optimum programla aynı performans özelliğine ve ayrıca bazı ek yüke sahip olacaktır. Tepegöz genellikle en aza indirilebilir.

Bununla birlikte, başlangıçta yalnızca OOP endişeleri ile tasarlanmış, temellerle ilgili olmaksızın , bir program başlangıçta en uygun düzeyde olabilir. Alt iyimserlik bazen yeniden düzenleme yoluyla çıkarılabilir; bazen tam bir yeniden yazma gerektirmez.

Dikkat: İş yazılımında performans önemli mi?

Evet, ancak büyüklük dereceleriyle pazara sunma süresi (TTM) daha önemlidir. İş yazılımı, kodun karmaşık iş kurallarına uyarlanabilirliğine vurgu yapar. Performans ölçümleri, geliştirme yaşam döngüsü boyunca alınmalıdır. (Bkz. Bölüm: optimal performans ne anlama geliyor? ) Yalnızca pazarlanabilir geliştirmeler yapılmalı ve sonraki sürümlerde aşamalı olarak kullanılmalıdır.

Optimum performans ne anlama geliyor?

Genel olarak, yazılım performansındaki sorun şudur: "daha hızlı bir sürümün var olduğunu" kanıtlamak için, önce bu daha hızlı sürümün ortaya çıkması gerekir (yani kendisinden başka bir kanıt yoktur).

Bazen bu daha hızlı sürüm ilk önce farklı bir dilde veya paradigmada görülür. Bu, diğer bazı dillerin veya paradigmaların aşağılık yargısı olarak değil, iyileştirmenin bir ipucu olarak alınmalıdır.

Optimum performans arayışımızı engelleyebiliyorsa neden OOP yapıyoruz?

OOP, "işlenebilirliği" ve dolayısıyla kodun iş değerini artırmak için ek yükü (uzayda ve yürütmede) sunar. Bu, daha fazla geliştirme ve optimizasyon maliyetini azaltır. Bakınız @MikeNakis .

OOP'nin hangi kısımları başlangıçta optimal olmayan bir tasarımı teşvik edebilir?

OOP'nin (i) basitliği / sezgiselliği teşvik eden kısımları, (ii) temeller yerine konuşma diline özgü tasarım yöntemlerinin kullanılması, (iii) aynı amaca yönelik çok sayıda özel uygulamayı cesaretlendirir.

  • ÖPMEK
  • YAGNI
  • KURU
  • Temel ilkelere eşit düşünmeden nesne tasarımı (örn. CRC kartları ile)

Bazı OOP yönergelerinin sıkı bir şekilde uygulanması (kapsülleme, mesaj iletme, bir şeyi iyi yapın) ilk başta daha yavaş kodla sonuçlanacaktır. Performans ölçümleri bu sorunların teşhis edilmesine yardımcı olacaktır. Veri yapısı ve algoritma, teorinin öngördüğü optimum tasarıma uygun olduğu sürece, genel gider genellikle en aza indirilebilir.

OOP genel giderlerine yönelik ortak azalmalar nelerdir?

Daha önce belirtildiği gibi, tasarıma en uygun veri yapılarını kullanmak.

Bazı diller, bazı çalışma zamanı performansını kurtarabilecek kod satırlamayı destekler.

Performanstan ödün vermeden OOP'u nasıl benimseyebiliriz?

Hem OOP hem de temel bilgileri öğrenin ve uygulayın.

OOP'ye sıkı sıkıya bağlı kalmanın daha hızlı bir sürüm yazmanızı engelleyebileceği doğrudur. Bazen daha hızlı bir versiyon sadece sıfırdan yazılabilir. Bu nedenle, farklı algoritmalar ve paradigmalar (OOP, genel, fonksiyonel, matematiksel, spagetti) kullanarak kodun birden çok sürümünü yazmaya yardımcı olur ve ardından her sürümü gözlemlenen maksimum performansa dönüştürmek için optimizasyon araçlarını kullanır.

OOP'den yararlanamayacak kod türleri var mı?

([@Quant_dev], [@ SK-logic] ve [@MikeNakis] arasındaki tartışmadan genişledi)

  1. Matematik kaynaklı sayısal tarifler.
    • Matematiksel denklemler ve dönüşümleri nesneler olarak anlaşılabilir.
    • Etkili yürütülebilir kod oluşturmak için çok karmaşık kod dönüştürme tekniklerine ihtiyaç vardır. Saf ("beyaz tahta") uygulaması dipsiz performans gösterecektir.
    • Ancak, günümüzün ana derleyicileri bunu yapamaz.
    • Özel yazılımlar (MATLAB ve Mathematica, vb.) Hem JIT hem de sembolik çözücüler bazı alt problemler için verimli kod üretebilir. Bu uzman çözücüler, kendileri bir OOP tasarımından yararlanacak olan özel amaçlı derleyiciler (insan tarafından okunabilir kod ile makineye yürütülebilir kod arasındaki aracılar) olarak görülebilir.
    • Her alt problem kendi "derleyici" ve "kod dönüşümlerini" gerektirir. Bu nedenle, her yıl yeni sonuçların ortaya çıktığı çok aktif bir açık araştırma alanıdır.
    • Araştırmalar uzun zaman aldığından, yazılım yazarları kağıt üzerinde optimizasyon yapmak ve optimize edilmiş kodu yazılıma dönüştürmek zorundadır. Kopyalanan kod gerçekten anlaşılmaz olabilir.
  2. Çok düşük seviye kodu.
      *

8

Bu aslında kaplar gibi nesne yönelimi ile ilgili değildir. Video oynatıcınızda pikselleri saklamak için çift bağlantılı bir liste kullandıysanız, bu durum acı çeker.

Ancak, doğru kapsayıcı kullanırsanız, bir std :: vector'un bir diziden daha yavaş olmasının bir nedeni yoktur ve bunun için zaten tüm ortak algoritmalara sahip olduğunuzdan - uzmanlar tarafından - muhtemelen ev haddelenmiş dizi kodunuzdan daha hızlıdır.


1
Derleyiciler alt optimal olduğundan (veya programlama dilinin kuralları belirli varsayımlardan veya optimizasyonlardan yararlanmayı yasaklar), gerçekten kaldırılamayan bir ek yük vardır. Ayrıca, vektörizasyon gibi belirli optimizasyonlar, OOP'nin geliştirebileceği veya engelleyebileceği veri organizasyonu gereksinimlerine (örneğin, yapılar dizisi yerine dizilerin yapısı) sahiptir. (Kısa bir süre önce bir std :: vector optimizasyon görevi üzerinde çalıştım.)
rwong

5

OOP açıkçası iyi bir fikirdir ve iyi bir fikir gibi aşırı kullanılabilir. Benim tecrübelerime göre aşırı kullanılmış. Kötü performans ve zayıf bakım sonuçları.

Sanal işlevleri çağırmanın yükü ile ilgisi yoktur ve optimizer / jitter'in yaptığı şeyle ilgisi yoktur.

En iyi big-O performansına sahip olmakla birlikte, çok kötü sabit faktörlere sahip olan veri yapıları ile ilgili her şeye sahiptir. Bu uygulamada herhangi bir performans sınırlayıcı sorun varsa, başka bir yerde olduğu varsayımı üzerine yapılır.

Bu tezahür etmenin bir yolu , O (1) performansına sahip olduğu varsayılan ancak yüzlerce ila binlerce komutu (eşleşen silme veya GC süresi dahil) gerçekleştirebilen, saniyede yeni kaç kez gerçekleştirildiğidir . Bu, kullanılmış nesneler kaydedilerek azaltılabilir, ancak kod daha az "temiz" olur.

Bu tezahürün başka bir yolu, insanların özellik işlevleri, bildirim işleyicileri, temel sınıf işlevlerine çağrılar, tutarlılığı korumak için var olan her türlü yeraltı işlev çağrısı yazmaya teşvik edilmesidir. Tutarlılığı korumak için sınırlı başarıya sahiptirler, ancak döngüleri boşa harcamada çılgınca başarılıdırlar. Programcılar normalleştirilmiş veri kavramını anlar, ancak sadece veritabanı tasarımına uygulama eğilimindedirler. Bunu veri yapısı tasarımına uygulamıyorlar, en azından kısmen OOP onlara zorunda olmadıklarını söylüyor. Bir nesnede Modifiye biti ayarlamak kadar basit bir şey, veri yapısı üzerinden yapılan güncellemelerin bir tsunamisine neden olabilir, çünkü koduna değecek hiçbir sınıf bir Modifiye çağrısı almaz ve sadece saklar .

Belli bir uygulamanın performansı, yazıldığı gibi iyi olabilir.

Öte yandan, bir performans sorunu varsa, onu nasıl ayarlayacağımın bir örneği . Bu çok aşamalı bir süreç. Her aşamada, bazı belirli etkinlikler büyük bir zaman diliminden sorumludur ve yerini daha hızlı bir şey alabilir. (Ben "darboğaz" demedim. Bunlar profilerlerin bulmakta iyi olduğu şeyler değildir.) Bu işlem, veri yapısının hızlandırılması, toptan değiştirilmesini sağlamak için sıklıkla gerektirir. Genellikle veri yapısı sadece OOP uygulaması önerildiği için vardır.


3

Teoride, yavaşlığa yol açabilir, ancak o zaman bile yavaş bir algoritma olmaz, yavaş bir uygulama olur. Pratikte, nesne yönelimi çeşitli olursa olsun senaryolarını denemenize (veya gelecekte algoritmayı tekrar ziyaret etmenize) izin verir ve böylece algoritmik iyileştirmeler sağlar; çünkü görev korkutucu olurdu. (Aslında her şeyi yeniden yazmanız gerekir.)

Örneğin, çeşitli görevleri ve varlıkları temiz kesimli nesnelere bölerek, daha sonra kolayca gelebilir ve diyelim ki, bazı nesneler arasında (onlara saydam olan) bin- kat iyileştirme.

Genel olarak, düşük düzeyli bir dil (veya yüksek düzeyli bir dile sahip akıllı hileler) kullanarak elde edebileceğiniz iyileştirme türleri, büyük oh notasyonu açısından şekil vermeyen sabit (doğrusal) zaman iyileştirmeleri sağlar. Algoritmik iyileştirmelerle doğrusal olmayan iyileştirmeler elde edebilirsiniz. Bu paha biçilemez.


1
+1: spagetti ve nesne yönelimli kod (veya iyi tanımlanmış bir paradigmada yazılmış kod) arasındaki fark şudur: yeniden yazılan iyi kodun her sürümü soruna yeni bir anlayış getirir. Yeniden yazılan her spagetti versiyonu hiçbir zaman içgörüyü getirmez.
rwong

@rwong daha iyi açıklayamadı ;-)
umlcat

3

Ancak bu OOP, performansa dayalı yazılım için bir dezavantaj olabilir mi, yani program ne kadar hızlı çalışır?

Genellikle evet !!! FAKAT...

Başka bir deyişle, birçok farklı nesne arasında birçok referans veya birçok sınıftan birçok yöntem kullanılması "ağır" bir uygulama ile sonuçlanabilir mi?

Şart değil. Bu dile / derleyiciye bağlıdır. Örneğin, sanal işlevleri kullanmamanız koşuluyla, optimize edilen bir C ++ derleyicisi, nesnenizi genel olarak sıfıra indirir. intOraya bir sarmalayıcı veya düz bir eski işaretçinin üzerine, bu düz eski veri türlerini doğrudan kullanmak kadar hızlı performans gösteren kapsamlı bir akıllı işaretçi yazmak gibi şeyler yapabilirsiniz .

Java gibi diğer dillerde, bir nesneye biraz genel bir yük vardır (çoğu durumda genellikle küçüktür, ancak gerçekten ufacık nesnelerle bazı nadir durumlarda astronomiktir). Örneğin Integer, çok daha az verimlidir int(64 bit'te 4 yerine 16 bayt alır). Ancak bu sadece bariz bir atık ya da bu tür bir şey değildir. Buna karşılık, Java her kullanıcı tanımlı tür üzerinde tekdüze yansıma gibi şeyler ve aynı zamanda işaretlenmemiş herhangi bir işlevi geçersiz kılma yeteneği sunar final.

Yine de en iyi senaryoyu ele alalım: Nesne arabirimlerini sıfır ek yüke kadar optimize edebilen optimize eden C ++ derleyicisi . O zaman bile, OOP genellikle performansı düşürecek ve zirveye ulaşmasını engelleyecektir. Bu tam bir paradoks gibi gelebilir: nasıl olabilir? Sorun şurada yatmaktadır:

Arayüz Tasarımı ve Kapsülleme

Sorun, bir derleyici bir nesnenin yapısını sıfır ek yüküne kadar ezebilse bile (C ++ derleyicilerini optimize etmek için en azından genellikle doğrudur), ince taneli nesnelerin kapsülleme ve arayüz tasarımı (ve biriken bağımlılıklar) genellikle kitleler tarafından toplanması amaçlanan nesneler için en uygun veri gösterimleri (genellikle performans açısından kritik yazılımlar için geçerlidir).

Bu örneği ele alalım:

class Particle
{
public:
    ...

private:
    double birth;                // 8 bytes
    float x;                     // 4 bytes
    float y;                     // 4 bytes
    float z;                     // 4 bytes
    /*padding*/                  // 4 bytes of padding
};
Particle particles[1000000];     // 1mil particles (~24 megs)

Diyelim ki bellek erişim düzenimiz, bu parçacıklar boyunca sırayla döngü yapmak ve bunları tekrar tekrar her çerçevenin etrafında hareket ettirmek, ekranın köşelerinden sekmek ve ardından sonucu oluşturmaktır.

Zaten birthparçacıklar bitişik bir şekilde toplandığında elemanı düzgün bir şekilde hizalamak için göze çarpan 4 baytlık bir dolgu yükü görebiliriz . Zaten belleğin ~% 16.7'si hizalama için kullanılan ölü alanla boşa harcanmaktadır.

Bu çok tartışmalı görünebilir çünkü bugünlerde gigabayt DRAM var. Yine de bugün sahip olduğumuz en çirkin makineler bile, CPU önbelleğinin (L3) en yavaş ve en büyük bölgesi söz konusu olduğunda yalnızca 8 megabayta sahiptir . Oraya ne kadar az sığabilirsek, tekrarlanan DRAM erişimi açısından daha fazla ödeme yaparız ve daha yavaş şeyler olur. Aniden, hafızanın% 16,7'sini boşa harcamak artık önemsiz bir anlaşma gibi görünmüyor.

Alan hizalaması üzerinde herhangi bir etkisi olmadan bu ek yükü kolayca ortadan kaldırabiliriz:

class Particle
{
public:
    ...

private:
    float x;                     // 4 bytes
    float y;                     // 4 bytes
    float z;                     // 4 bytes
};
Particle particles[1000000];     // 1mil particles (~12 megs)
double particle_birth[1000000];  // 1mil particle births (~8 bytes)

Şimdi hafızayı 24 megavattan 20 megavat'a düşürdük. Sıralı erişim düzeniyle, makine şimdi bu verileri biraz daha hızlı tüketecektir.

Ama bu birthalana biraz daha yakından bakalım . Bir parçacığın doğduğu (yaratıldığı) başlangıç ​​zamanını kaydettiğini varsayalım. Alana yalnızca bir parçacık ilk oluşturulduğunda ve bir parçacığın ölüp ölmeyeceğini ve ekranda rastgele bir yerde yeniden doğup doğmayacağını görmek için her 10 saniyede bir erişildiğini düşünün. Bu durumda, birthsoğuk bir alandır. Kritik performans döngülerimizde erişilmez.

Sonuç olarak, gerçek performans açısından kritik veriler 20 megabayt değil, aslında 12 megabayt bitişik bir bloktur. Sık eriştiğimiz gerçek sıcak bellek , boyutunun yarısına küçüldü ! Orijinal, 24 megabaytlık çözümümüz üzerinde önemli hızlanmalar bekleyin (ölçülmesine gerek yok - bu tür şeyleri zaten binlerce kez yaptık, ancak şüpheniz varsa çekinmeyin).

Yine de burada ne yaptığımıza dikkat edin. Bu parçacık nesnesinin kapsüllenmesini tamamen kırdık. Durumu artık bir Particletürün özel alanları ile ayrı, paralel bir dizi arasında bölünür . İşte bu noktada ayrıntılı nesne yönelimli tasarım ön plana çıkıyor.

Tek bir parçacık, tek bir piksel, hatta tek bir 4 bileşenli vektör, hatta bir oyundaki tek bir "yaratık" nesnesi gibi tek, çok parçalı bir nesnenin arayüz tasarımı ile sınırlı olduğunda optimum veri sunumunu ifade edemeyiz. Bir çita hızı, 2 metrekarelik ufacık bir adada duruyorsa ve nesne yönelimli tasarımın performans açısından genellikle yaptığı şey budur. Veri sunumunu en uygun olmayan bir nitelikle sınırlar.

Bunu daha da ileri götürmek için, sadece parçacıkları hareket ettirdiğimizden, x / y / z alanlarına üç ayrı döngüden erişebildiğimizi varsayalım. Bu durumda, 8 SPFP işlemini paralel olarak vektörleştirebilen AVX kayıtlarıyla SoA tarzı SIMD içsellerinden yararlanabiliriz. Ancak bunu yapmak için şimdi bu temsili kullanmalıyız:

float particle_x[1000000];       // 1mil particle X positions (~4 megs)
float particle_y[1000000];       // 1mil particle Y positions (~4 megs)
float particle_z[1000000];       // 1mil particle Z positions (~4 megs)
double particle_birth[1000000];  // 1mil particle births (~8 bytes)

Şimdi parçacık simülasyonuyla uçuyoruz, ama parçacık tasarımımıza ne olduğuna bakın. Tamamen yıkıldı ve şimdi 4 paralel diziye bakıyoruz ve onları bir araya getirecek bir nesne yok. Nesneye yönelik Particletasarımımız sayonara gitti.

Bu, kullanıcıların hız talep ettikleri ve sadece doğruluklarının daha fazla talep ettikleri tek şey olduğu, performans açısından kritik alanlarda çalıştığım için birçok kez oldu. Bu ufacık nesneye yönelik tasarımların yıkılması gerekiyordu ve basamaklı kırılmalar genellikle daha hızlı tasarıma doğru yavaş bir kullanımdan çıkarma stratejisi kullanmamızı gerektiriyordu.

Çözüm

Yukarıdaki senaryo yalnızca ayrıntılı nesne yönelimli tasarımlarla ilgili bir sorun sunmaktadır . Bu durumlarda, genellikle SoA temsilcileri, sıcak / soğuk alan bölme, sıralı erişim kalıpları için dolgu azaltma sonucu daha verimli temsiller ifade etmek için yapıyı yıkmak zorunda kalıyoruz (dolgu bazen rastgele erişimli performans için yararlıdır AoS vakalarında kalıplar, ancak neredeyse her zaman sıralı erişim kalıpları için bir engel) vb.

Yine de, yerleştiğimiz son temsili alabilir ve yine de nesne yönelimli bir arayüzü modelleyebiliriz:

// Represents a collection of particles.
class ParticleSystem
{
public:
    ...

private:
    double particle_birth[1000000];  // 1mil particle births (~8 bytes)
    float particle_x[1000000];       // 1mil particle X positions (~4 megs)
    float particle_y[1000000];       // 1mil particle Y positions (~4 megs)
    float particle_z[1000000];       // 1mil particle Z positions (~4 megs)
};

Şimdi iyiyiz. Sevdiğimiz tüm nesne yönelimli güzellikleri alabiliriz. Çita mümkün olduğunca hızlı koşmak için bir ülkeye sahiptir. Arayüz tasarımlarımız artık bizi darboğaz köşesine sıkıştırmıyor.

ParticleSystempotansiyel olarak soyut bile olabilir ve sanal işlevleri kullanabilir. Şimdi tartışmalı , parçacık başına değil, parçacık toplama seviyesinde ek yükü ödüyoruz . Tepegöz, tek tek parçacık düzeyinde nesneleri modellersek, bunun ne olacağının 1 / 1.000.000'i kadardır.

Bu, ağır bir yükü işleyen gerçek performans açısından kritik alanlarda ve her türlü programlama dili için çözümdür (bu teknik C, C ++, Python, Java, JavaScript, Lua, Swift, vb. Arayüz tasarımı ve mimarisi ile ilgili olduğu için kolayca "erken optimizasyon" olarak etiketlenemez . Tek bir parçacığı, bir istemci yükü bağımlılığına sahip bir nesne olarak modelleyen bir kod tabanı yazamıyoruzParticle'sve daha sonra zihnimizi değiştirelim. Eski kod tabanlarını optimize etmek için çağrıldığımda çok şey yaptım ve bu, hantal tasarımını kullanmak için on binlerce kod satırını dikkatlice yeniden yazmanız gerekebilir. Bu ideal olarak, ağır bir yük öngörebilmemiz koşuluyla, ön plana çıkma şeklimizi etkiler.

Bu yanıtı birçok performans sorusunda, özellikle de nesne yönelimli tasarımla ilgili bir biçimde ya da başka bir şekilde yankılamaya devam ediyorum. Nesne yönelimli tasarım yine de en yüksek talep performans performansıyla uyumlu olabilir, ancak bununla ilgili düşünme şeklimizi biraz değiştirmeliyiz. Bu çitaya olabildiğince hızlı çalışması için bir yer vermeliyiz ve herhangi bir durumu zar zor saklayan ufacık küçük nesneler tasarlarsak bu genellikle imkansızdır.


Fantastik. OOP'u yüksek performans talebi ile birleştirmek için aradığım şey buydu. Neden daha fazla oy verilmediğini gerçekten anlayamıyorum.
pbx

2

Evet, hem algoritmik hem de uygulama düzeyinde yüksek performanslı programlama söz konusu olduğunda nesne yönelimli zihniyet kesinlikle nötr veya negatif olabilir. OOP algoritmik analizin yerini alırsa, sizi erken uygulamaya yönlendirebilir ve en düşük seviyede OOP soyutlamaları bir kenara bırakılmalıdır.

Konu, OOP'un bireysel örnekler üzerinde düşünmeye yaptığı vurgudan kaynaklanıyor. Bir algoritma hakkında OOP düşünme biçiminin, belirli bir değerler kümesi düşünerek ve bu şekilde uygulamak olduğunu söylemek doğru olur. Bu en üst düzey yolunuzsa, Büyük O kazanımlarına yol açacak bir dönüşüm veya yeniden yapılandırma gerçekleştirmeniz olası değildir.

Algoritmik düzeyde, genellikle daha büyük resmi ve Big O kazançlarına yol açan değerler arasındaki kısıtlamaları veya ilişkileri düşünür. Örnek olarak, OOP zihniyetinde "sürekli bir tamsayılar toplamını" bir döngüden(max + min) * n/2

Uygulama düzeyinde, bilgisayarlar çoğu uygulama seviyesi algoritması için "yeterince hızlı" olmasına rağmen, düşük seviyeli performans açısından kritik kodda, yerellik hakkında çok endişelenir. Yine, OOP, bireysel bir örnek üzerinde düşünmeye vurgu yapar ve döngüden bir geçişin değerleri negatif olabilir. Yüksek performanslı kodda, düz bir döngü yazmak yerine, döngüyü kısmen açmak, üstte birkaç yükleme talimatını gruplandırmak, sonra bunları bir grupta dönüştürmek ve daha sonra bir grupta yazmak isteyebilirsiniz. Ara hesaplara ve büyük ölçüde önbellek ve bellek erişimine dikkat ederken; OOP soyutlamalarının artık geçerli olmadığı sorunlar. Ve eğer takip edilirse, yanıltıcı olabilir: bu seviyede, makine seviyesi temsillerini bilmeli ve düşünmelisiniz.

Intel'in Performans İlkeleri gibi bir şeye baktığınızda, kelimenin tam anlamıyla Fast Fourier Dönüşümü'nün binlerce uygulamasına sahipsiniz , her biri belirli bir veri boyutu ve makine mimarisi için daha iyi çalışmak için ayarlandı. (Büyüleyici bir şekilde, bu uygulamaların büyük kısmının makine tarafından üretildiği ortaya çıkıyor: Markus Püschel Otomatik Performans Programlama )

Tabii ki, cevapların çoğunun söylediği gibi, çoğu geliştirme için, çoğu algoritma için, OOP performansla ilgisizdir. "Zamanından önce kötümser" olmadığınız ve çok sayıda yerel olmayan arama eklemediğiniz sürece, thisişaretçi ne burada ne de oradadır.


0

Onunla ilgili ve çoğu zaman gözden kaçan.

Bu kolay bir cevap değil , ne yapmak istediğinize bağlı.

Bazı algoritmalar düz yapılandırılmış programlama kullanarak performans açısından daha iyidir, diğerleri ise nesne yönelimi kullanarak daha iyidir.

Nesne Oryantasyonundan önce, birçok okul yapısal programlama ile algoritma tasarımını öğretir. Bugün, birçok okul, algoritma tasarımı ve performansını göz ardı ederek nesne yönelimli programlama öğretir.

Tabii ki, yapılandırılmış programlama öğreten, algoritmaları umursamayan okullar burada.


0

Performansın hepsi CPU ve bellek döngülerine geliyor. Ancak OOP mesajlaşma ve kapsülleme yükü ile daha geniş bir açık programlama semantiği arasındaki yüzde farkı, uygulamanızın performansında gözle görülür bir fark yaratacak kadar önemli bir yüzde olabilir veya olmayabilir. Bir uygulama disk veya veri önbellek kaçırma bağlıysa, gürültüde herhangi bir OOP yükü tamamen kaybolabilir.

Ancak, gerçek zamanlı sinyal ve görüntü işleme ve diğer sayısal hesaplama bağlantılı uygulamaların iç döngülerinde, fark, herhangi bir OOP yükünü yürütmeyi çok daha maliyetli hale getirebilecek CPU ve bellek döngülerinin önemli bir yüzdesi olabilir.

Belirli bir OOP dilinin semantiği, derleyicinin bu döngüleri optimize etmesi veya CPU'nun şube tahmin devrelerinin her zaman doğru tahmin etmesi ve bu döngüleri ön getirme ve boru hattı ile örtmesi için yeterli fırsatları ortaya çıkarabilir veya göstermeyebilir.


0

İyi bir nesne yönelimli tasarım, bir uygulamayı önemli ölçüde hızlandırmama yardımcı oldu. A algoritmik bir şekilde karmaşık grafikler üretmek zorundaydı. Microsoft Visio otomasyonu ile yaptım. Çalıştım, ama inanılmaz derecede yavaştı. Neyse ki, mantık (algoritma) ve Visio şeyleri arasına ekstra bir soyutlama seviyesi ekledim. Visio bileşenim işlevselliğini bir arabirim aracılığıyla ortaya çıkardı. Bu, yavaş bileşeni, en az 50 kat daha hızlı olan başka bir SVG dosyası oluşturarak kolayca değiştirmeme izin verdi! Temiz bir nesne yönelimli yaklaşım olmasaydı, algoritmanın ve Görme kontrolünün kodları, değişikliği bir kabusa dönüştürecek şekilde dolaşmış olurdu.


Yani prosedürel bir dille veya OO Tasarım ve OO programlama diliyle uygulanan OO Design mı demek istediniz?
umlcat

Bir C # uygulamasından bahsediyorum. Hem tasarım hem de dil OO'dur. Dilin OOessizliği bazı küçük performans isabetleri (sanal yöntem çağrıları, nesne oluşturma, arayüz üzerinden üye erişimi) sunacağı için, OO tasarımı çok daha hızlı bir uygulama oluşturmamda bana yardımcı oldu. Söylemek istediğim şey: OO (dil ve tasarım) nedeniyle performans hitlerini unutun. Milyonlarca yineleme ile ağır hesaplamalar yapmadığınız sürece, OO size zarar vermez. Genellikle çok zaman kaybettiğiniz G / Ç.
Olivier Jacot-Descombes
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.