Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
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:
- Visual Studio'nun CPU Kullanımı aracını kullanarak bir CPU kullanımı izlemesi ile başlayın. Visual Studio'nun CPU Kullanımı aracı, performans araştırmaları için iyi bir başlangıç noktasıdır.
- Bellek ve veritabanı analizi için ek izlemeler toplayın:
- Bellek içgörüleri için .NET Nesne Ayırma aracını kullanın.
- SQL sorgularını ve zamanlamalarını incelemek için Veritabanı aracını kullanın.
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.
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 (), 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.
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.
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.
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.
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.
GetBlogTitleX
kaynak 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 veforeach
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.
İ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.
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.
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!
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.
- Örnek olay incelemesi: Performans sorununu izole etme
- Örnek Olay İncelemesi: 30 dakikadan kısa sürede iki kat performans
- Yeni Enstrümantasyon Aracı ile Visual Studio performansını iyileştirme