Performansı arttırmak için hangi basit teknikleri kullanıyorsunuz?


21

Kodunuzu okumayı zorlaştırmadan performansı geliştirmek için basit rutin yazma yöntemimizden bahsediyorum ... örneğin, öğrendiklerimiz için tipik olan:

for(int i = 0; i < collection.length(); i++ ){
   // stuff here
}

Ancak, genellikle foreachuygulanabilir olmadığı durumlarda yapıyorum :

for(int i = 0, j = collection.length(); i < j; i++ ){
   // stuff here
}

Bence bu daha iyi bir yaklaşım çünkü lengthmetodu sadece bir kez arayacak ... kız arkadaşım bunun şifreli olduğunu söylüyor. Kendi gelişmelerinde kullandığın başka basit bir numara var mı?


34
+1 sadece kodunuz net olmadığında size söyleyecek bir kız arkadaşı olması için
Kristo

76
Bunu bize bir kız arkadaşın olduğunu söylemek için gönderiyorsun.
Josh K

11
@Hristiyan: Bunu sizin için yapabilecek derleyici optimizasyonları olduğunu unutmayın, böylece yalnızca okunabilirliği etkileyebilir ve performansı etkilemeyebilirsiniz; erken optimizasyon tüm kötülüklerin kökenidir ... Aynı satırda birden fazla beyan veya ödevden kaçınmaya çalışın, insanları iki kez okumalarını sağlayın ... Normal yolu kullanmalısınız (ilk örneğinizi) veya for döngüsü dışındaki ikinci bildirim (bu, j'nin ne anlama geldiğini görmek için tekrar okumanız gerekebileceği gibi okunabilirliği de azaltır).
Tamara Wijsman

5
@TomWij: Doğru (ve tam) alıntı: "Küçük verimleri unutmalıyız, zamanın yaklaşık% 97'sini söylemeliyiz: erken optimizasyon tüm kötülüklerin kökenidir. Ancak bu kritik% 3'teki fırsatlarımızı kaçırmamalıyız. "
Robert Harvey

3
@tomwij: Eğer yüzde üçünü harcıyorsanız, tanımı gereği zaman açısından kritik kodda yapıyor olmalısınız ve zamanınızı diğer yüzde 97'ye harcamak zorunda değilsiniz.
Robert Harvey

Yanıtlar:


28

erken-tartışma-tüm-kötülük dersinin kökenidir-

Bununla birlikte, gereksiz verimden kaçınmak için edindiğim bazı alışkanlıklar var ve bazı durumlarda kodumu daha basit ve daha doğru hale getirdim.

Bu, genel prensiplerin bir tartışması değil, gereksiz verimsizlikleri koda eklemekten kaçınmanın farkında olması gereken bazı hususların tartışılmasıdır.

Büyük O'nu bilin

Bu muhtemelen yukarıdaki uzun tartışmalarla birleştirilmelidir. İç döngünün hesaplamayı tekrarladığı bir döngünün içindeki bir döngünün daha yavaş olacağı çok yaygın bir anlam ifade eder. Örneğin:

for (i = 0; i < strlen(str); i++) {
    ...
}

Eğer dize gerçekten uzunsa bu, korkunç bir zaman alacaktır, çünkü uzunluk döngünün her yinelemesinde yeniden hesaplanır. GCC'nin aslında bu durumu en iyi duruma getirdiğine dikkat edin, çünkü strlen()saf bir işlev olarak işaretlenmiş.

Bir milyon 32-bit tamsayı sıralama , kabarcık sıralama gitmek yanlış yol olacaktır . Genel olarak, sıralama O (n * log n) zamanında yapılabilir (veya daha iyisi, radix sıralama durumunda), bu nedenle verilerinizin küçük olacağını bilmiyorsanız, en azından O (n) olan bir algoritma arayın. * log n).

Aynı şekilde, veritabanlarıyla uğraşırken, endekslerin farkında olun. Siz SELECT * FROM people WHERE age = 20ve insanlar (yaş) hakkında bir endeksiniz yoksa, daha hızlı bir O (log n) indeks taramasından ziyade O (n) sıralı bir taramayı gerektirir.

Tamsayılı aritmetik hiyerarşisi

C de programlama yaparken, bazı aritmetik işlemlerin diğerlerinden daha pahalı olduğunu unutmayın. Tamsayılar için, hiyerarşi bu gibi bir şey gider (önce en ucuzu):

  • + - ~ & | ^
  • << >>
  • *
  • /

Verildiği takdirde, derleyici genellikle bir ana bilgisayarı hedefliyorsanız otomatik olarak n / 2yapmak gibi şeyleri optimize eder n >> 1, ancak gömülü bir cihazı hedefliyorsanız bu lüksü elde edemeyebilirsiniz.

Ayrıca, % 2ve & 1farklı anlambilim var. Bölünme ve modül, genellikle sıfıra doğru yuvarlanır, ancak uygulama tanımlanır. İyi ol ' >>ve &her zaman negatif sonsuzluğa yuvarlanır ki bence çok daha mantıklı geliyor. Örneğin, bilgisayarımda:

printf("%d\n", -1 % 2); // -1 (maybe)
printf("%d\n", -1 & 1); // 1

Dolayısıyla, mantıklı olanı kullanın. % 2Aslen yazmaya giderken kullanarak iyi bir çocuk olduğunu düşünmeyin & 1.

Pahalı kayan nokta işlemleri

Özellikle tam sayılarla uğraşırken, onlara gerçekten de gerekmeyen kod gibi pow()ve zorlu kayan nokta işlemlerinden kaçının log(). Örneğin, bir sayı okurken şunları yapın:

int parseInt(const char *str)
{
    const char *p;
    int         digits;
    int         number;
    int         position;

    // Count the number of digits
    for (p = str; isdigit(*p); p++)
        {}
    digits = p - str;

    // Sum the digits, multiplying them by their respective power of 10.
    number = 0;
    position = digits - 1;
    for (p = str; isdigit(*p); p++, position--)
        number += (*p - '0') * pow(10, position);

    return number;
}

Sadece bu kullanımı pow()(ve onu kullanması gereken int<-> doubledönüşümleri) oldukça pahalı olmakla kalmaz, aynı zamanda hassasiyet kaybı için bir fırsat yaratır (bu arada, yukarıdaki kodun hassas sorunları yoktur). Bu yüzden matematiksel olmayan bir bağlamda kullanılan bu tür bir işlev gördüğümde inanıyorum.

Ayrıca, her yinelemede 10 ile çarpılan aşağıdaki "akıllı" algoritmanın aslında yukarıdaki koddan daha özlü olduğuna dikkat edin:

int parseInt(const char *str)
{
    const char *p;
    int         number;

    number = 0;
    for (p = str; isdigit(*p); p++) {
        number *= 10;
        number += *p - '0';
    }

    return number;
}

Çok kapsamlı cevap.
Paddyslacker

1
Erken optimizasyon tartışmasının çöp kodu için geçerli olmadığını unutmayın. Her zaman ilk etapta iyi çalışan bir uygulama kullanmalısınız.

GCC'nin gerçekte bu durumu en iyi duruma getirdiğine dikkat edin, çünkü strlen () saf bir işlev olarak işaretlenir. Sanırım bunun saf değil de bir const fonksiyonu olduğunu söylüyorsun.
Andy Lester

@Andi Lester: Aslında, saf demek istedim. GCC belgelerinde , bir const işlevinin global belleği okuyamadığı için const'ın saf değerden biraz daha katı olduğunu belirtir. strlen()işaretçi argümanı ile gösterilen dizgiyi inceler, yani const olamaz. Ayrıca, strlen()gerçekten de glibc'lerde saf olarak işaretlenmiştirstring.h
Joey Adams

Haklısın, benim hatam ve iki kez kontrol etmeliydim. Parrot projesi üzerinde açıklama işlevlerini ya pureda consthatta başlık dosyasında belgeleyen işlevler üzerinde çalışıyorum , ikisi arasındaki ince fark yüzünden. docs.parrot.org/parrot/1.3.0/html/docs/dev/c_functions.pod.html
Andy Lester

13

Sorunuzdan ve yorum dizisinden, bu kod değişikliğinin performansı artırdığını "sanıyor" gibi görünüyorsunuz, ancak bunu yapıp yapmadığını bilmiyorsunuz.

Kent Beck'in felsefesinin hayranıyım :

"Çalışmasını sağla, doğru yap, hızlı yap."

Kod performansını geliştirme tekniğim, öncelikle birim testlerinden geçen kodu almak ve iyi faktörlendirilmiş ve sonra (özellikle döngü işlemleri için) performansı kontrol eden bir birim testi yazmak ve ardından kodu yeniden gözden geçirmek veya farklı bir algoritma düşünmek ve seçilen beklendiği gibi çalışmıyor.

Örneğin, hızı .NET koduyla test etmek için, belirli bir yönteme yapılan bir aramanın belirli bir süre içinde yürütüleceğini iddia etmek için NUnit'in Timeout özelliğini kullanırım.

NUnit'in zaman aşımı özniteliğini verdiğiniz kod örneğiyle (ve döngü için çok sayıda yineleme) kullandığınızda, koda yaptığınız "iyileştirme" işleminin gerçekten bu döngünün performansına yardımcı olup olmadığını kanıtlayabilirsiniz.

Bir sorumluluk reddi: Bu “mikro” seviyede etkili olsa da, performansı test etmenin tek yolu bu değildir ve “makro” seviyesinde ortaya çıkabilecek sorunları dikkate almaz - ama bu iyi bir başlangıçtır.


2
Profil oluşturmaya büyük bir inancım olsa da, Cristian'in aradığı ipuçlarını tutmanın akıllıca olduğuna inanıyorum. Daima eşit derecede okunabilir iki yöntemin hızını seçeceğim. Olgunlaşma sonrası optimizasyona zorlanmak eğlenceli değildir.
AShelly

Ünite testlerine mutlaka gerek yoktur, ancak bazı performans efsanelerinin doğru olup olmadığını kontrol etmek için her zaman bu 20 dakikayı harcamakta fayda vardır, çünkü özellikle cevap genellikle -O ve -g bayrağının derleyicisine ve durumuna bağlıdır (veya Debug / VS durumunda serbest bırakın).
mbq

+1 Bu cevap, sorumla ilgili yorumumu tamamlıyor.
Tamara Wijsman

1
@AShelly: Eğer döngü sözdiziminin basit reformları hakkında konuşuyorsak, bunu yaptıktan sonra değiştirmek çok kolaydır. Ayrıca, aynı derecede okunabilir bulduğunuz şey diğer programcılar için böyle olmayabilir. "Standart" sözdizimini mümkün olduğunca kullanmak en iyisidir ve yalnızca gerekli olduğunda kanıtlayın.
Joeri Sebrechts

@AShelly kesinlikle iki eşit okunabilir yöntem düşünebilirseniz ve sadece işinizi yapmadığınız daha az verimli olanı seçtiyseniz? Bunu gerçekten yapan var mı?
glenatron

11

Derleyicinizin iyi dönebileceğini unutmayın:

for(int i = 0; i < collection.length(); i++ ){
   // stuff here
}

içine:

int j = collection.length();
for(int i = 0; i < j; i++ ){
   // stuff here
}

veya collectiondöngü üzerinde değişmemişse benzer bir şey .

Bu kod, uygulamanızın kritik bir bölümünde ise, bunun olup olmadığını veya bunun için derleyici seçeneklerini değiştirip değiştiremeyeceğinizi öğrenmeye değer.

Bu, size birkaç ekstra makine devri kazandırırken, kodun okunabilirliğini koruyacaktır (birincisi çoğu insanın görmeyi beklediği gibi). Derleyicinin size yardımcı olamayacağı diğer alanlara yoğunlaşmakta özgürsünüz.

Bir yandan not: collectionDöngü içinde elementleri ekleyerek veya çıkararak değiştirirseniz (evet, bunun kötü bir fikir olduğunu biliyorum ama olur) o zaman ikinci örneğin tüm öğelerin üzerinden geçmeyecek veya geçmişe erişmeye çalışacaktır. dizinin sonu.


1
Neden sadece açıkça yapmıyorsun?

3
Sınırları kontrol eden bazı dillerde, açıkça yaparsanız kodunuzu YAVAŞTIRIR. Collection.length için bir döngü ile derleyici sizin için dışarı taşır ve sınır kontrolünü atlar. Uygulamanızın herhangi bir yerindeki bazı sabit noktalara bir döngü yaparak, her yinelemeyi sınırlandıracaksınız. Bu yüzden ölçmek önemlidir - performans hakkındaki sezgi neredeyse hiçbir zaman doğru değildir.
Kate Gregory

1
Bu yüzden “keşfedilmeye değer” dedim.
ChrisF

C # derleyicisi, collection.length () 'nin, coll.pop () yönteminde olduğu gibi koleksiyonda değişiklik yapmadığını nasıl bilebilir? Derleyicinin bunu optimize ettiğini varsaymak yerine IL'yi kontrol etmenin en iyi yol olacağını düşünüyorum. C ++ 'da bir yöntemi const (' nesneyi değiştirmez ') olarak işaretleyebilirsiniz, böylece derleyici bu optimizasyonu güvenli bir şekilde yapabilir.
JBRWilkinson

1
@JBRW Bunu yapan eniyileyiciler ayrıca koleksiyonların yöntemlerinin C ++ 'ın olmasa bile, ok-let-it-constness-olsa bile-farkında olduğunun farkındalar. Ne de olsa, sadece bir şeyin bir koleksiyon olduğunu fark edip edemeyeceğinizi ve uzunluğunu nasıl alacağınızı bilip bilmediğinizi kontrol edebilirsiniz.
Kate Gregory

9

Bu tür bir optimizasyon genellikle önerilmez. Bu optimizasyon parçası derleyici tarafından kolayca yapılabilir, montaj yerine daha yüksek seviyeli bir programlama dili ile çalışıyorsunuz, aynı seviyede düşünün.


1
Programlama hakkında ona bir kitap verin;)
Joeri Sebrechts

1
+1, çoğu kız arkadaşımızın Leydi Gaga ile kod açıklığından çok daha fazla ilgilendiği için.
haploid

Neden önerilmediğini açıklayabilir misiniz?
Macneil

@macneil iyi ... bu hile kodları bu kadar yaygın ve tamamen işe yaramaz hale getirir, bu optimizasyon parçası derleyici tarafından yapılması gerekiyordu.
taktoth

@macneil daha yüksek bir dilde çalışıyorsanız, aynı seviyede düşünün.
taktoth

3

Bu genel amaçlı kodlama için çok fazla geçerli olmayabilir, ancak bugünlerde çoğunlukla gömülü geliştirme yapıyorum. Belirli bir hedef işlemcimiz (daha hızlı olmayacak - sistemi 20+ yıl içinde emekli olduklarında çok eski görünecek gibi) ve kodun çoğu için çok kısıtlayıcı zamanlama süreleri var. İşlemci, tüm işlemciler gibi, hangi işlemlerin hızlı veya yavaş olduğu konusunda bazı tuhaflıklar vardır.

Tüm ekip için okunabilirliği korurken, en verimli kodu oluşturduğumuzdan emin olmak için kullanılan bir tekniğimiz var. En doğal dil yapısının en verimli kodu üretmediği yerlerde, en uygun kodun kullanılmasını sağlayan makrolar oluşturduk. Farklı bir işlemci için bir takip projesi yaparsak, bu işlemcideki en uygun yöntem için makroları güncelleyebiliriz.

Spesifik bir örnek olarak, mevcut işlemcimiz için dallar boru hattını boşaltarak işlemciyi 8 döngü boyunca durdurur. Derleyici bu kodu alır:

 bool isReady = (value > TriggerLevel);

ve onu montaj eşdeğerine dönüştürür

isReady = 0
if (value > TriggerLevel)
{
  isReady = 1;
}

Bu işlem 3 devir ya da atlarsa 10 alır isReady=1;. Ancak işlemcinin bir tek çevrim maxtalimatı vardır, bu yüzden her zaman 3 döngü alacağı garanti edilen bu diziyi oluşturmak için kod yazmak daha iyidir:

diff = value-TriggerLevel;
diff = max(diff, 0);
isReady = min(1,diff);

Açıkçası, buradaki amaç orijinalden daha az açık. Böylece ne zaman bir Boolean Greater-Than karşılaştırması istiyorsak kullandığımız bir makro yarattık:

#define BOOL_GT(a,b) min(max((a)-(b),0),1)

//isReady = value > TriggerLevel;
isReady = BOOL_GT(value, TriggerLevel);

Diğer karşılaştırmalar için benzer şeyler yapabiliriz. Bir yabancı için, kod yalnızca doğal yapıyı kullandığımızdan biraz daha az okunabilir. Bununla birlikte, kodla çalışmak için biraz zaman harcadıktan sonra hızla netleşir ve her programcının kendi optimizasyon teknikleriyle denemesine izin vermekten çok daha iyidir.


3

İlk tavsiye, kodda ne olduğunu tam olarak anlayana kadar bu tür erken optimizasyonlardan kaçınmak olacaktır, böylece daha hızlı ve daha yavaş yapmadığınızdan emin olursunuz.

Örneğin, C # 'da, bir dizinin uzunluğunu ilmek ediyorsanız, diziye eriştiğinizde dizini kontrol etmek için menzili kontrol etmek zorunda olmadığını bildiği için derleyici kodu optimize edecektir. Dizi uzunluğunu bir değişkene koyarak optimize etmeye çalışırsanız, döngü ve dizi arasındaki bağlantıyı koparacak ve kodu gerçekten çok daha yavaş hale getireceksiniz.

Mikro-optimizasyon yapacaksanız, kendinizi çok fazla kaynak kullandığı bilinen şeylerle sınırlandırmanız gerekir. Eğer sadece hafif bir performans kazancı varsa, bunun yerine en okunaklı ve bakımı yapılabilir kodla devam etmelisiniz. Bilgisayarın çalışması zaman içinde nasıl değiştiğine göre, şimdi öğrendiğiniz bir şey biraz daha hızlıdır, bu şekilde kalmayabilir.


3

Çok basit bir tekniğim var.

  1. Kodumu çalıştırıyorum.
  2. Hız için test ediyorum.
  3. Hızlıysa, başka bir özellik için 1. adıma geri döneceğim. Eğer yavaşsa, tıkanıklığı bulmak için profilini çıkarırım.
  4. Darboğazı tamir ediyorum. 1. adıma geri dönün.

Bu süreci atlatmanın zaman kazandığı birçok zaman vardır, ancak genel olarak böyle olup olmadığını anlarsınız. Şüphe varsa, varsayılan olarak buna bağlıyım.


2

Kısa devre avantajından yararlanın:

if(someVar || SomeMethod())

kodlama kadar uzun sürüyor ve şu şekilde okunabilir:

if(someMethod() || someVar)

yine de zamanla daha hızlı bir şekilde değerlendirecek.


1

Altı ay bekle, patronuna herkese yeni bilgisayarlar almasını sağla. Ciddi anlamda. Programcı süresi uzun vadede donanımdan çok daha pahalıdır. Yüksek performanslı bilgisayarlar, kodlayıcıların hız konusunda endişe duymadan basit bir şekilde kod yazmasına izin verir.


6
Er ... Müşterilerinizin gördüğü performans nedir? Onlar için yeni bilgisayarlar satın alacak kadar zengin misiniz?
Robert Harvey

2
Ve neredeyse performans duvarına çarptık; çok çekirdekli hesaplama tek çıkış yoludur, ancak beklemek programlarınızı kullanmayacaktır.
mbq

+1 Bu cevap, sorumla ilgili yorumumu tamamlıyor.
Tamara Wijsman

3
Binlerce veya milyonlarca kullanıcınız olduğunda hiçbir programlama süresi donanımdan daha pahalı değildir. Programlayıcı zamanı, kullanıcı zamanından daha önemli DEĞİLDİR, bunu en kısa zamanda kafanızdan geçirin.
HLGEM

1
İyi alışkanlıklara dalın, o zaman her zaman yaptığınız gibi herhangi bir programcı zaman almaz.
Dominique McDonnell

1

Önceden çok fazla optimize etmemeye çalışın, ardından optimize ettiğinizde okunabilirlik konusunda biraz daha az endişelenin.

Orada çok az, gereksiz karmaşıklıktan nefret ediyorum, ancak karmaşık bir duruma çarptığınızda karmaşık bir çözüme ihtiyaç duyuluyor.

Kodu en açık şekilde yazarsanız, karmaşık değişikliği yaptığınızda neden değiştirildiğini açıklayan bir yorum yapın.

Ancak, sizin anlamınıza göre, Boolean'ı varsayılan yaklaşımın tersine yaparken çoğu zaman bazen yardımcı olur:

for(int i = 0, j = collection.length(); i < j; i++ ){
// stuff here
}

olabilir

for(int i = collection.length(); i > 0; i-=1 ){
// stuff here
}

Birçok dilde "şeyler" bölümüne uygun ayarlamalar yaptığınız sürece ve hala okunabilir durumdadır. Soruna, çoğu insanın ilk önce yapmayı düşündüğü gibi yaklaşmıyor çünkü geriye sayıyor.

Örneğin c # 'da:

        string[] collection = {"a","b"};

        string result = "";

        for (int i = 0, j = collection.Count() - 1; i < j; i++)
        {
            result += collection[i] + "~";
        }

ayrıca şu şekilde de yazılabilir:

        for (int i = collection.Count() - 1; i > 0; i -= 1)
        {
            result = collection[i] + "~" + result;
        }

(ve evet, bunu bir birleşme veya stringbuilder ile yapmalısınız, ama basit bir örnek yapmaya çalışıyorum)

Kullanılması zor olan birçok ipucu var, ancak dize yeniden atanma cezasını önlemek veya metin dosyalarını ikili modda okumaktan kaçınmak için eski vb. Dosya bir readtoend için çok büyük olduğunda arabelleğe alma cezasını geçmek için.

Her yere uygulayabileceğimi düşünebileceğim tek genel durum, bir Boole cebirini, denklemi kısa devre koşullu şartlardan yararlanma veya karmaşık hale getirme şansına sahip olan bir şeye dönüştürmeye çalışmak için karmaşık koşullara uygulamak olacaktır. tamamen iç içe geçmiş if-o zaman veya case deyimlerini bir denklemin içine yerleştirin. Bunların hiçbiri her durumda işe yaramaz, ancak önemli ölçüde zaman kazandırabilirler.


bu bir çözümdür, ancak derleyici, çoğu yaygın sınıf uzunluğu için () imzasız bir tür döndürdüğü için
uyarıcıları tükürecektir

Ancak endeksi tersine çevirerek yinelemenin kendisi daha karmaşık hale gelebilir.
Tamara Wijsman

@stijn Yazdığımda c # 'yi düşünüyordum, ama belki de bu öneri aynı zamanda dile özgü bir kategoriye giriyor - editöre bakınız ... Bu riski taşımaz. Eğer // eşyalarınız bir çeşit yığın manipülasyonu ise, mantığı doğru bir şekilde tersine çevirmek bile mümkün olmayabilir, ancak çoğu durumda IMHO'yu dikkatlice yaparsanız, kafa karıştırıcı olabilir ve kafa karıştırıcı olmaz.
Bill

haklısın; C ++ 'da hala' normal 'döngüyü tercih ederim ama yinelemenin dışına çıkarılan uzunluk () çağrısı (const size_t len ​​= collection.length ()' de olduğu gibi; (size_t i = 0; i <len; ++ i) {}) iki nedenden ötürü: 'normal' ileri sayma döngüsünün daha okunaklı / anlaşılabilir olduğunu tespit ettim (ancak bu muhtemelen daha yaygın olması nedeniyle) ve döngü değişmez uzunluğu () döngüsünün dışına çıkarılmasını sağlar.
stijn

1
  1. Profil. Bir sorunumuz var mı? Nerede?
  2. Bir şekilde G / Ç ile ilişkili olduğu% 90 durumlarda, önbellekleme uygulayın (ve belki daha fazla bellek elde edin)
  3. Eğer CPU ile ilgiliyse, önbelleklemeyi uygula
  4. Eğer performans hala bir sorunsa, basit teknikler alanından ayrıldık - matematiği yapın.

1

Bulabileceğiniz en iyi araçları kullanın - iyi derleyici, iyi profilleyici, iyi kitaplıklar. Algoritmaları doğru alın veya daha iyisi - sizin için doğru kütüphaneyi kullanın. Önemsiz döngü optimizasyonları küçük patateslerdir, ayrıca optimizasyon derleyicisi kadar akıllı değilsinizdir.


1

En basit olanı, mümkünse, ortak bir durum kullanım modeli bir dizi uyuyorsa (0, 64), ancak küçük bir üst sınırı olmayan nadir durumlarda olduğunda yığını kullanmak benim için en basit olanı.

Basit C örneği (daha önce):

void some_hotspot_called_in_big_loops(int n, ...)
{
    // 'n' is, 99% of the time, <= 64.
    int* values = calloc(n, sizeof(int));

    // do stuff with values
    ...
    free(values);
}

Ve sonra:

void some_hotspot_called_in_big_loops(int n, ...)
{
    // 'n' is, 99% of the time, <= 64.
    int values_mem[64] = {0}
    int* values = (n <= 64) ? values_mem: calloc(n, sizeof(int));

    // do stuff with values
    ...
    if (values != values_mem)
        free(values);
}

Bunu genelleştirdim, çünkü bu tür sıcak noktalar profil oluşturmada çok fazla mahsul oluyor:

void some_hotspot_called_in_big_loops(int n, ...)
{
    // 'n' is, 99% of the time, <= 64.
    MemFast values_mem;
    int* values = mf_calloc(&values_mem, n, sizeof(int));

    // do stuff with values
    ...

    mf_free(&values_mem);
}

Yukarıdaki,% 99.9 durumlarda tahsis edilen veriler yeterince küçük olduğunda yığını kullanır ve aksi halde yığını kullanır.

C ++ 'da bunu SmallVectoraynı kavram etrafında dönen standart uyumlu küçük bir diziyle ( oradaki uygulamalara benzer şekilde ) genelleştirdim .

Bu epik bir optimizasyon değil (örneğin, bir işlemin 1.8 saniyeye kadar tamamlanması için 3 saniyeden itibaren bir indirim aldım), ancak uygulamak için bu kadar önemsiz bir çaba gerektiriyor. Sadece bir kod satırı tanıtarak ve ikisini değiştirerek 3 saniyeden 1.8 saniyeye kadar bir şey bulabildiğinizde, bu kadar küçük bir para için oldukça iyi bir patlama olur.


0

Uygulamanız üzerinde çok büyük bir etkisi olacak verilere erişirken yapabileceğiniz pek çok performans değişikliği var. Bir veritabanına erişmek için sorgular yazar veya bir ORM kullanırsanız, kullandığınız veritabanı arka uçları için bazı performans ayar kitaplarını okumanız gerekir. Muhtemel kötü performans gösteren teknik kullanıyorsunuz. Bunu yapmak için cehalet dışında hiçbir sebep yoktur. Bu erken bir optimizasyon değildir (bunu söyleyen adamı lanetliyorum çünkü performans konusunda hiç endişe duymayacak kadar yaygın bir şekilde karıştı.), Bu iyi bir tasarım.

SQL Server için sadece hızlı bir performans geliştirici örneği: Uygun dizinler kullanın, imleçlerden kaçının - set tabanlı mantığı kullanın, cümlelerin bulunduğu yerlerde sargable kullanın, görünümlerin üstüne görünüm atmayın, ihtiyaç duyduğunuzdan daha fazla veri döndürmeyin İhtiyacınız olan sütunları, ilişkili alt sorguları kullanmayın.


0

Eğer bu C ++ ise, ++iyerine alışkanlık edinmelisin i++. ++iAsla daha kötüye gitmeyecek, bu tek başına bir ifadeyle tamamen aynı olduğu anlamına gelir ve bazı durumlarda performans iyileştirmesi olabilir.

Yardımcı olma ihtimali üzerine mevcut kodu değiştirmeye değmez, ancak girmesi iyi bir alışkanlıktır.


0

Ben biraz farklı almak var. Buraya gelmenizin sadece tavsiyelerine uymak çok fazla fark yaratmayacak, çünkü yapmanız gereken bazı hatalar var, sonra düzeltmeniz gereken, sonradan öğrenmeniz gereken bazı hatalar var.

Yapmanız gereken hata, veri yapınızı herkesin yaptığı gibi tasarlamak. Yani, gereksiz veriler ve birçok soyutlama katmanı ile, onu tutarlı tutmaya çalışan yapı boyunca yayılan özellikler ve bildirimlerle.

O zaman sen , performans ayarlama (profilleme) yapmanız ve birçok yönden size, maliyetlerinize neyin mal olduğunu, soyutlamanın birçok katmanının nasıl olduğunu, yapısını tutarlı tutmaya çalışan yapı boyunca yayılan özellik ve bildirimleri nasıl gösterdiğini göstermeniz gerekir.

Kodda büyük değişiklikler yapmadan bu sorunları bir şekilde düzeltebilirsiniz.

O zaman şanslıysanız, daha az veri yapısının daha iyi olduğunu ve birçok şeyi mesajların dalgaları ile sıkı bir şekilde uyum içinde tutmaya çalışmaktan ziyade geçici tutarsızlığa tahammül etmenin daha iyi olduğunu öğrenebilirsiniz.

Döngü yazmanın onunla hiçbir ilgisi yok.

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.