Aracılığıyla paylaş


Örnek Olay İncelemesi: Kodu iyileştirme ve işlem maliyetlerini azaltmaya yönelik başlangıç kılavuzu (C#, Visual Basic, C++, F#)

Kodunuzu iyileştirmek işlem süresini ve maliyetlerini azaltır. Bu örnek olay incelemesi, örnek bir .NET uygulamasındaki performans sorunlarını belirlemek ve düzeltmek için Visual Studio profil oluşturma araçlarının nasıl kullanılacağını göstermektedir. Profil oluşturma araçlarını karşılaştırmak istiyorsanız bkz. Hangi aracı seçmeliyim?

Bu kılavuz aşağıdakileri kapsar:

  • Performansı analiz etmek ve geliştirmek için Visual Studio profil oluşturma araçlarını kullanma.
  • CPU kullanımını, bellek ayırmayı ve veritabanı etkileşimlerini iyileştirmeye yönelik pratik stratejiler.

Kendi uygulamalarınızı daha verimli hale getirmek için bu teknikleri uygulayın.

İyileştirme örnek olay incelemesi

Örnek .NET uygulaması, Entity Framework kullanarak blogların ve gönderilerin SQLite veritabanına karşı sorgular çalıştırır. Gerçek dünya veri alma senaryosu simülasyonu yaparak birçok sorgu yürütür. Uygulama , Entity Framework kullanmaya başlama örneğini temel alır, ancak daha büyük bir veri kümesi kullanır.

Önemli performans sorunları şunlardır:

  • Yüksek CPU Kullanımı: Verimsiz hesaplamalar veya işleme görevleri CPU tüketimini ve maliyetlerini artırır.
  • Verimsiz Bellek Ayırma: Yetersiz bellek yönetimi aşırı çöp toplamaya ve performansın düşmesine neden olur.
  • Veritabanı Ek Yükleri: Verimsiz sorgular ve aşırı veritabanı çağrıları performansı düşürür.

Bu örnek olay incelemesi, bu sorunları saptamak ve çözmek için Visual Studio profil oluşturma araçlarını kullanarak uygulamayı daha verimli ve uygun maliyetli hale getirmeyi amaçlar.

Meydan okuma

Bu performans sorunlarını çözmek için çeşitli zorluklar vardır:

  • Performans Sorunlarını Tanılama: Yüksek CPU, bellek veya veritabanı ek yüklerinin kök nedenlerini belirlemek için profil oluşturma araçlarının etkili bir şekilde kullanılması ve sonuçların doğru yorumlanması gerekir.
  • Bilgi ve Kaynak Kısıtlamaları: Profil oluşturma ve iyileştirme, her zaman kullanılamayabilecek belirli beceriler ve deneyim gerektirir.

Bu zorlukların üstesinden gelmek için profil oluşturma araçlarını, teknik bilgileri ve dikkatli testleri birleştiren stratejik bir yaklaşım temel öneme sahiptir.

Strateji

Bu örnek olay incelemesindeki yaklaşımın üst düzey bir görünümü aşağıdadır:

Veri toplama aşağıdaki görevleri gerektirir:

  • Uygulamayı Yayın sürümü olarak ayarlayın.
  • Performans Profili Oluşturucu'da (Alt+F2) CPU Kullanımı aracını seçin.
  • Performans Profili Oluşturucu'da uygulamayı başlatın ve bir iz toplayın.

Yüksek CPU kullanımı alanlarını inceleme

CPU Kullanımı aracıyla bir izleme topladıktan ve Visual Studio'ya yükledikten sonra, önce özetlenmiş verileri gösteren ilk .diagsession rapor sayfasını denetleriz. Raporda Ayrıntıları Aç bağlantısını kullanın.

CPU Kullanımı aracındaki açma ayrıntılarının ekran görüntüsü.

Rapor ayrıntıları görünümünde Çağrı Ağacı görünümünü açın. Uygulamadaki en yüksek CPU kullanımına sahip kod yolu, sıcak yol olarak adlandırılır. Sıcak yol alev simgesi (Sıcak Yol simgesini gösteren ekran görüntüsü.), iyileştirilebilir performans sorunlarını hızla belirlemenize olanak tanır.

Çağrı Ağacı görünümünde, uygulamanın CPU kullanımının yaklaşık 60% paylaşımını kullanarak uygulamadaki GetBlogTitleX yöntemi için yüksek CPU kullanımı görebilirsiniz. Ancak, için GetBlogTitleX değeri düşük, yalnızca .10%civarında. Toplam CPUaksine, Self CPU değeri diğer işlevlerde harcanan zamanı dışlar, bu nedenle gerçek darboğazı bulmak için çağrı ağacının daha aşağısına bakmamız gerektiğini biliriz.

CPU Kullanımı aracındaki Çağrı Ağacı görünümünün ekran görüntüsü.

GetBlogTitleX, çok yüksek Self CPU değerleriyle kanıtlandığı gibi CPU süresinin çoğunu kullanan iki LINQ DLL'sine dış çağrılar yapar. Bu, LINQ sorgusunun iyileştirilecek bir alan olabileceğine ilişkin ilk ipucudur.

CPU Kullanımı aracındaki Çağrı Ağacı görünümünün, Self CPU'nun vurgulandığı ekran görüntüsü.

Görselleştirilmiş çağrı ağacını ve verilerin farklı bir görünümünü almak için Flame Graph görünümünü açın. (Veya GetBlogTitleX sağ tıklayıp Alev Grafiğinde Görüntüle seçin.) Burada da GetBlogTitleX yöntemi, uygulamanın CPU kullanımının büyük bir kısmından (sarı renkle gösterilir) sorumlu gibi görünüyor. LINQ DLL'lerine yapılan dış çağrılar GetBlogTitleX kutusunun altında gösterilir ve yöntemi için tüm CPU süresini kullanır.

CPU Kullanımı aracında Alev Grafiği görünümünün ekran görüntüsü.

Ek veri toplama

Genellikle, diğer araçlar analize yardımcı olmak ve sorunu yalıtmak için ek bilgiler sağlayabilir. Bu örnek olay incelemesinde aşağıdaki yaklaşımı benimsiyoruz:

  • İlk olarak bellek kullanımına bakın. Yüksek CPU kullanımı ile yüksek bellek kullanımı arasında bir bağıntı olabileceğinden, sorunu yalıtmak için her ikisine de bakmak yararlı olabilir.
  • LINQ DLL'lerini tanımladığımız için Veritabanı aracına da göz atacağız.

Bellek kullanımını denetleme

Uygulamada bellek kullanımı açısından neler olduğunu görmek için .NET Nesne Ayırma aracını kullanarak bir izleme toplarız (C++ için bunun yerine Bellek Kullanımı aracını kullanabilirsiniz). Bellek izlemesindeki Çağrı Ağacı görünümü sık erişimli yolu gösterir ve yüksek bellek kullanımı alanını belirlememize yardımcı olur. Bu noktada sürpriz değil, GetBlogTitleX yöntemi çok fazla nesne oluşturuyor gibi görünüyor! Aslında 900.000'den fazla nesne tahsisi.

.NET Nesne Ayırma aracında Çağrı Ağacı görünümünün ekran görüntüsü .

Oluşturulan nesnelerin çoğu dizeler, nesne dizileri ve Int32'lerdir. Kaynak kodu inceleyerek bu türlerin nasıl oluşturulduğunu görebiliriz.

Veritabanı aracında sorguyu denetleme

Performans Profili Oluşturucu'da CPU Kullanımı yerine Veritabanı aracını seçiyoruz (veya her ikisini de seçiyoruz). İz topladığımızda tanılama sayfasındaki Sorgular sekmesini açın. Veritabanı izlemesinin Sorgular sekmesinde, ilk satırın en uzun sorguyu (2446 ms) gösterdiğini görebilirsiniz. Kayıtları sütunu, sorgunun kaç kayıt okuduğunu gösterir. Bu bilgileri daha sonra karşılaştırmak için kullanabilirsiniz.

Veritabanı aracındaki Veritabanı sorgularının ekran görüntüsü.

Sorgu sütununda LINQ tarafından oluşturulan SELECT deyimini inceleyerek, ilk satırı GetBlogTitleX yöntemiyle ilişkili sorgu olarak tanımlarız. Tam sorgu dizesini görüntülemek için sütun genişliğini genişletin. Tam sorgu dizesi şöyledir:

SELECT "b"."Url", "b"."BlogId", "p"."PostId", "p"."Author", "p"."BlogId", "p"."Content", "p"."Date", "p"."MetaData", "p"."Title"
FROM "Blogs" AS "b" LEFT JOIN "Posts" AS "p" ON "b"."BlogId" = "p"."BlogId" ORDER BY "b"."BlogId"

Uygulamanın burada ihtiyacımızdan çok daha fazla sütun değeri aldığına dikkat edin. Şimdi kaynak koduna bakalım.

Kodu iyileştirme

GetBlogTitleX kaynak koduna göz atma zamanı geldi. Veritabanı aracında sorguya sağ tıklayın ve Kaynak Dosyaya Gitseçeneğini seçin. GetBlogTitleXkaynak kodunda, veritabanını okumak için LINQ kullanan aşağıdaki kodu buluyoruz.

foreach (var blog in db.Blogs.Select(b => new { b.Url, b.Posts }).ToList())
  {
    foreach (var post in blog.Posts)
    {
      if (post.Author == "Fred Smith")
      {
        Console.WriteLine($"Post: {post.Title}");
      }
  }
}

Bu kod, veritabanında yazar olarak "Fred Smith" ile tüm blogları aramak için foreach döngüleri kullanır. Buna baktığınızda, bellekte çok sayıda nesnenin oluşturulduğunu görebilirsiniz: veritabanındaki her blog için yeni bir nesne dizisi, her URL için ilişkili dizeler ve gönderilerde yer alan özelliklerin değerleri (blog kimliği gibi).

Biraz araştırma yapıyoruz ve LINQ sorgularını iyileştirmeye yönelik bazı yaygın öneriler buluyoruz. Alternatif olarak, zaman kazandırabilir ve Copilot'un bizim için araştırma yapmasına izin verebiliriz.

Copilot kullanıyorsak bağlam menüsünden Copilot'a sor seçip aşağıdaki soruyu yazarız:

Can you make the LINQ query in this method faster?

Bahşiş

Copilot için iyi sorular oluşturmaya yardımcı olmak için /optimize gibi eğik çizgi komutlarını kullanabilirsiniz.

Bu örnekte, Copilot aşağıdaki önerilen kod değişikliklerini ve bir açıklamayı sunar.

public void GetBlogTitleX()
{
    var posts = db.Posts
        .Where(post => post.Author == "Fred Smith")
        .Select(post => post.Title)
        .ToList();

    foreach (var postTitle in posts)
    {
        Console.WriteLine($"Post: {postTitle}");
    }
}

Bu kod, sorguyu iyileştirmeye yardımcı olacak çeşitli değişiklikler içerir:

  • Where hükmü eklendi ve foreach döngülerinden biri ortadan kaldırıldı.
  • Yalnızca Select deyimindeki Title özelliğini yansıttık. Bu örnekte ihtiyacımız olan tek şey budur.

Ardından profil oluşturma araçlarını kullanarak yeniden test edeceğiz.

Sonuçlar

Kodu güncelleştirdikten sonra, bir izleme toplamak için CPU Kullanımı aracını yeniden çalıştırırız. Çağrı Ağacı görünümü, GetBlogTitleX'nin yalnızca 1754 ms çalıştığını ve uygulamanın CPU toplamının 37% kullandığını ve 59%'den önemli bir gelişme olduğunu gösterir.

CPU Kullanımı aracının Çağrı Ağacı görünümünde geliştirilmiş CPU kullanımının ekran görüntüsü.

İyileştirmeyi gösteren başka bir görselleştirme görmek için Alev Grafiği görünümüne geçin. Bu görünümde GetBlogTitleX CPU'nun daha küçük bir bölümünü de kullanır.

CPU Kullanımı aracının Alev Grafiği görünümünde geliştirilmiş CPU kullanımının ekran görüntüsü.

Veritabanı aracı izleme çıktısındaki sonuçları kontrol edin ve bu sorgu kullanılarak 100.000 kayıt yerine yalnızca iki kayıt okundu! Ayrıca, sorgu çok basitleştirilmiştir ve daha önce oluşturulan gereksiz LEFT JOIN'i ortadan kaldırır.

Veritabanı aracında daha hızlı sorgu süresinin ekran görüntüsü.

Daha sonra .NET Nesne Ayırma aracındaki sonuçları yeniden kontrol ediyoruz ve GetBlogTitleX'ın yalnızca 56.000 nesne ayırımından sorumlu olduğunu, bunun da 900.000'den neredeyse 95% oranında bir azaltmayı ifade ettiğini görüyoruz!

.NET Nesne Ayırma aracındaki azaltılmış bellek ayırmalarının ekran görüntüsü.

Yinele

Birden çok iyileştirme gerekebilir ve hangi değişikliklerin performansı iyileştirdiğini görmek ve işlem maliyetini azaltmaya yardımcı olmak için kod değişiklikleriyle yinelemeye devam edebiliriz.

Sonraki adımlar

Aşağıdaki makaleler ve blog gönderileri, Visual Studio performans araçlarını etkili bir şekilde kullanmayı öğrenmenize yardımcı olacak daha fazla bilgi sağlar.