Örnek Olay İncelemesi: Kodu iyileştirme ve işlem maliyetlerini azaltmaya yönelik başlangıç kılavuzu (C#, Visual Basic, C++, F#)
İşlem sürenizi azaltmak maliyetleri düşürmek anlamına gelir, bu nedenle kodunuzu iyileştirmek tasarruf sağlayabilir. Bu örnek olay incelemesi, verimliliği artırmak için profil oluşturma araçlarının nasıl kullanılacağını göstermek için performans sorunlarıyla birlikte örnek bir uygulama kullanır. Profil oluşturma araçlarını karşılaştırmak istiyorsanız bkz . Hangi aracı seçmeliyim?
Bu örnek olay incelemesi şu konuları kapsar:
- Kod iyileştirmenin önemi ve işlem maliyetlerini azaltma üzerindeki etkisi.
- Uygulama performansını analiz etmek için Visual Studio profil oluşturma araçlarını kullanma.
- Performans sorunlarını belirlemek için bu araçlar tarafından sağlanan verileri yorumlama.
- CPU kullanımına, bellek ayırmaya ve veritabanı etkileşimlerine odaklanarak kodu iyileştirmek için pratik stratejiler uygulama.
Bu teknikleri takip edin ve daha verimli ve uygun maliyetli hale getirmek için kendi uygulamalarınıza uygulayın.
İyileştirme örnek olay incelemesi
Bu örnek olay incelemesinde incelenen örnek uygulama, blog ve blog gönderilerinden oluşan bir veritabanında sorgular çalıştıran bir .NET uygulamasıdır. SQLite yerel veritabanıyla etkileşim kurmak için .NET için popüler bir ORM (Nesne-İlişkisel Eşleme) olan Entity Framework'i kullanır. Uygulama çok sayıda sorgu yürütecek şekilde yapılandırılmıştır ve kapsamlı veri alma görevlerini işlemek için bir .NET uygulamasının gerekebileceği gerçek dünya senaryosunu benzetmektedir. Örnek uygulama, Entity Framework kullanmaya başlama örneğinin değiştirilmiş bir sürümüdür.
Örnek uygulamayla ilgili birincil performans sorunu, işlem kaynaklarını yönetme ve veritabanıyla etkileşim kurma şeklidir. Uygulamanın verimliliğini ve sonuç olarak çalıştırmayla ilişkili işlem maliyetlerini önemli ölçüde etkileyen bir performans sorunu vardır. Sorun aşağıdaki belirtileri içerir:
Yüksek CPU Kullanımı: Uygulamalar, gereksiz yere çok fazla CPU kaynağı tüketecek şekilde verimsiz hesaplamalar veya işleme görevleri gerçekleştirebilir. Bu, yanıt sürelerinin yavaşlanmasına ve işletim maliyetlerinin artmasına neden olabilir.
Verimsiz Bellek Ayırma: Uygulamalar bazen bellek kullanımı ve ayırmayla ilgili sorunlarla karşılaşabilir. .NET uygulamalarında verimsiz bellek yönetimi, atık toplamanın artmasına neden olabilir ve bu da uygulama performansını etkileyebilir.
Veritabanı Etkileşimi Ek Yükleri: Bir veritabanında çok sayıda sorgu yürüten uygulamalar, veritabanı etkileşimleriyle ilgili performans sorunlarıyla karşılaşabilir. Bu, verimsiz sorguları, aşırı veritabanı çağrılarını ve Entity Framework özelliklerinin kötü kullanımını içerir ve bunların tümü performansı düşürebilir.
Örnek olay incelemesi, uygulamanın performansını analiz etmek için Visual Studio'nun profil oluşturma araçlarını kullanarak bu sorunları çözmeyi amaçlar. Geliştiriciler, uygulamanın performansının nerede ve nasıl iyileştirilebileceğini anlayarak CPU kullanımını azaltmak, bellek ayırma verimliliğini artırmak, veritabanı etkileşimlerini kolaylaştırmak ve kaynak kullanımını iyileştirmek için iyileştirmeler uygulayabilir. Nihai hedef, uygulamanın genel performansını geliştirerek çalıştırmayı daha verimli ve uygun maliyetli hale getirmektir.
Sınama
Örnek .NET uygulamasındaki performans sorunlarının giderilmesi çeşitli zorluklara neden olur. Bu zorluklar, performans sorunlarını tanılamanın karmaşıklığından kaynaklandı. Açıklanan sorunları düzeltmenin başlıca zorlukları şunlardır:
Performans Sorunlarını Tanılama: Başlıca zorluklardan biri, performans sorunlarının kök nedenlerini doğru bir şekilde belirlemektir. Yüksek CPU kullanımı, verimsiz bellek ayırma ve veritabanı etkileşimi ek yükleri birden çok katkıda bulunan faktöre sahip olabilir. Geliştiricilerin bu sorunları tanılamak için profil oluşturma araçlarını etkili bir şekilde kullanması gerekir. Bu, bu araçların nasıl çalıştığını ve çıkışlarını nasıl yorumlayacaklarını anlamanızı gerektirir.
Bilgi ve Kaynak Kısıtlamaları: Son olarak, ekipler bilgi, uzmanlık ve kaynaklarla ilgili kısıtlamalarla karşılaşabilir. Bir uygulamanın profilini oluşturmak ve iyileştirmek için belirli beceriler ve deneyim gerekir ve tüm ekiplerin bu kaynaklara hemen erişimi olmayabilir.
Bu zorlukların giderilmesi için profil oluşturma araçlarının etkin kullanımını, teknik bilgileri ve dikkatli planlama ve testleri birleştiren stratejik bir yaklaşım gerekir. Örnek olay incelemesi, geliştiricilere bu süreçte yol göstermeyi, bu zorlukların üstesinden gelmek ve uygulamanın performansını geliştirmek için stratejiler ve içgörüler sağlamayı amaçlar.
Strateji
Bu örnek olay incelemesindeki yaklaşımın üst düzey bir görünümü aşağıdadır:
- Araştırmayı CPU kullanım izlemesi alarak başlatırız. Visual Studio'nun CPU Kullanımı aracı genellikle performans araştırmalarına başlamak ve maliyeti azaltmak için kodu iyileştirmek için yararlıdır.
- Ardından, sorunları yalıtmaya veya performansı geliştirmeye yardımcı olacak ek içgörüler elde etmek için diğer profil oluşturma araçlarından birini kullanarak bir izleme toplarız. Örneğin:
- Bellek kullanımına göz atacağız. .NET için önce .NET Nesne Ayırma aracını deneyeceğiz. (.NET veya C++ için bunun yerine Bellek Kullanımı aracına bakabilirsiniz.)
- ADO.NET veya Entity Framework için Veritabanı aracını kullanarak SQL sorgularını, hassas sorgu süresini ve daha fazlasını inceleyebiliriz.
Veri toplama aşağıdaki görevleri gerektirir:
- Uygulamayı Yayın derlemesine ayarlama.
- Performans Profili Oluşturucu'dan CPU Kullanımı aracını seçme (Alt+F2). (Sonraki adımlarda diğer araçlardan birkaçı yer alır.)
- Performans Profili Oluşturucu'dan uygulamayı başlatın ve bir izleme 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. Rapordaki 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ık erişimli yol olarak adlandırılır. Sık erişimli yol alev simgesi () iyileştirilebilir performans sorunlarını hızla belirlemenize yardımcı olabilir.
Çağrı Ağacı görünümünde, uygulamanın CPU kullanımının yaklaşık %60'ını kullanarak uygulamadaki yöntem için GetBlogTitleX
yüksek CPU kullanımı görebilirsiniz. Ancak, için GetBlogTitleX
Self CPU değeri düşüktür, yalnızca yaklaşık %10'dur. Toplam CPU'dan farklı olarak, Self CPU değeri diğer işlevlerde harcanan zamanı dışlar, bu nedenle gerçek performans sorunu için çağrı ağacının daha aşağısına bakmayı biliyoruz.
GetBlogTitleX
çok yüksek Self CPU değerleri tarafından 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ş bir çağrı ağacı ve verilerin farklı bir görünümünü almak için Alev Grafiği görünümünü açın. (Alternatif olarak sağ tıklayıp GetBlogTitleX
Alev Grafiğinde Görüntüle'yi de seçebilirsiniz.) Burada da yöntemin GetBlogTitleX
uygulamanın CPU kullanımının büyük bir kısmından sorumlu olduğu (sarı renkle gösterilmiştir) gibi görünüyor. LINQ DLL'lerine yapılan dış çağrılar kutunun altında GetBlogTitleX
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ı tanımlamamıza yardımcı olur. Bu noktada şaşırtıcı değil, GetBlogTitleX
yöntemi çok fazla nesne oluşturuyor gibi görünüyor! Aslında 900.000'den fazla nesne ayırması.
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). bir izleme topladığımızda tanılama sayfasında 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 deyimi inceleyerek SELECT
, ilk satırı yöntemiyle GetBlogTitleX
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
Kaynak koduna göz GetBlogTitleX
atma zamanı geldi. Veritabanı aracında sorguya sağ tıklayın ve Kaynak Dosyaya Git'i seçin. için kaynak kodunda, veritabanını okumak için GetBlogTitleX
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 döngüleri kullanır foreach
. 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 kazanıp araştırmayı Bizim için Copilot'a bırakabiliriz.
Copilot kullanıyorsak bağlam menüsünden Copilot'a Sor'u seçip aşağıdaki soruyu yazarız:
Can you make the LINQ query in this method faster?
İpucu
Copilot için iyi sorular oluşturmaya yardımcı olması 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:
- yan tümcesi
Where
eklendi ve döngülerdenforeach
birini ortadan kaldırdı. - Yalnızca deyimindeki
Select
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ü, uygulamanın CPU toplamının %37'sini kullanarak yalnızca 1754 ms çalıştığını ve %59'dan önemli bir gelişme olduğunu gösterirGetBlogTitleX
.
İ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 CPU'nun GetBlogTitleX
daha küçük bir bölümünü de kullanır.
Veritabanı aracı izlemesindeki sonuçları denetleyin ve bu sorgu kullanılarak 100.000 yerine yalnızca iki kayıt okunur! 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 denetleyeceğiz ve yalnızca 56.000 nesne ayırmasından sorumlu olduğunu ve 900.000'den neredeyse %95 oranında azalma sağlandığını GetBlogTitleX
göreceğiz!
Yineleme
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 yalıtma
- Örnek Olay İncelemesi: 30 dakikanın altında çift performans
- Yeni İzleme Aracı ile Visual Studio performansını iyileştirme