Bu makale makine çevirisi ayna makalesidir, orijinal makaleye geçmek için lütfen buraya tıklayın.

Görünüm: 6317|Yanıt: 3

[Kaynak] [Dön]. NET performans optimizasyonları - List koleksiyonlarını hızlıca geçin

[Bağlantıyı kopyala]
2022-8-28 tarihinde yayınlandı 20:51:16 | | | |
Kısa giriş

System.Collections.Generic.List, .NET dilinde genel bir <T>koleksiyon sınıfıdır; kolaylığı ve zengin API'si sayesinde her türlü veriyi depolayabilir; bu API günlük yaşamımızda yaygın olarak kullanılır ve en çok kullanılan koleksiyon sınıfı olarak söylenebilir.

Kod yazarken, genellikle bir Liste <T>koleksiyonunu işin içinden bazı işleriyle ilgili öğeleri elde etmek için yineleme yapmamız gerekir. Normalde bir sette çok fazla unsur yoktur ve geçmek çok hızlıdır. Ama bazı büyük veri işleme, istatistik, gerçek zamanlı hesaplama vb<T>. için on binlerce ya da yüz binlerce verinin listesini hızlıca nasıl geçebilirsiniz? Bugün sizinle paylaşmam gereken şey bu.

Geçiş modu

Farklı geçiş yöntemlerinin performansına bakalım ve farklı büyüklük mertebesi toplama işlemleriyle farklı yöntemlerin performansını görmek için aşağıdaki performans kıyaslamasını oluşturalım. Kod parçası şöyle görünüyor:

Foreach ifadesini kullanın

foreach koleksiyonları en yaygın şekilde dolaştığımızdır, iterator deseninin sözdizimi şeker uygulamasıdır ve bu dönem için bir kıyaslama olarak da kullanılır.

Foreach ifadesi bir sözdizimi şekeri olduğundan, derleyici sonunda işlevselliği uygulamak için GetEnumerator() ve MoveNext() ile while döngüsü çağırır. Derlenmiş kod şöyle görünüyor:



MoveNext() yöntemi uygulaması, iterasyonda koleksiyonu değiştiren başka iş parçacığı olmamasını sağlar ve değişiklik gerçekleşirse InvalidOperationException istisnası çıkarır, mevcut indeksin meşru olup olmadığını kontrol etmek için taşma kontrolü yapılır ve ayrıca ilgili öğeyi enumeratora ataması gerekir. Güncel özellik,Yani aslında performansı en iyi değil, kod parçası şöyle görünüyor:



Farklı set boyutlarında nasıl performans gösterdiğine bakalım ve sonuçlar şöyle görünüyor:



Farklı boyutlarda, zaman alan sürecin doğrusal büyüme ilişkisinin gerektiği görülebilir; 100w veri işlem mantığı olmadan geçilse bile en az 1 saniye sürer.

ForEach List yöntemini kullanın

Bir diğer yaygın yol ise List <T>kullanmaktır. ForEach() yöntemi, bir Eylem <T>delegesini göndermenize olanak tanır; bu temsilci öğe boyunca ilerlerken Eylem delegesini <T>çağırır.

<T>List'in dahili bir uygulama yöntemidir, böylece özel dizilere doğrudan erişebilir ve taşma kontrollerinden kaçınabilir. Teoride, hızlı olmalı; Ancak bizim senaryomuzda sadece bir boş yöntem vardır ve bu, foreach yöntemine tamamen hatır içi çağrı ile iyi davranmayabilir. Aşağıda, taşma kontrolü olmadığını, ancak eşzamanlı sürüm numarası kontrolünü koruduğuna dair ForEach yönteminin kaynak kodu yer almaktadır.



Ayrıca, ForEach metoduna bir delege iletmek gerektiğinden, çağrı kodunda kapanış üretim sınıfındaki delege nesnesinin her seferinde boş olup olmadığını kontrol edecektir, yoksa yeni Action<T>(), aşağıda gösterildiği gibi kontrol edilir:



Performans açısından foreach anahtar kelime ile nasıl karşılaştırıldığında bir bakalım. Aşağıdaki görsel, kıyaslamanın sonuçlarını göstermektedir:



Test sonuçlarına bakılırsa, foreach anahtar kelimesini doğrudan kullanmaktan %40 daha yavaş, eğer gerekli değilse foreach kelimesini doğrudan kullanmak daha iyi bir tercih gibi görünüyor, yani daha hızlı bir yol var mı?

döngü geçişi için

En eski yöntemimize geri dönelim, yani for anahtar kelimesini kullanarak koleksiyonda dolaşıyoruz. Şu anda en iyi performans gösteren geçiş yöntemi olmalı, çünkü önceki kodlar gibi yedek kod gerektirmiyor (ancak indeksleyici de taşmanı önlemek için kontrol ediliyor) ve tabii ki sürüm numarasını kontrol etmiyor, bu yüzden çok iş parçacıklı ortamda koleksiyon değiştirilir ve for kullanılırken istisna olmaz. Test kodu şöyle görünüyor:

Nasıl sonuçlanacağını görelim.



Beklediğimiz gibi görünüyor.for döngüsünü doğrudan kullanmak, foreach ile karşılaştırıldığından %60 daha hızlıdır, eskiden 1 saniye süren bir set, şimdi sadece 400 milisaniye sürüyor. Peki daha hızlı bir yol var mı?

Koleksiyonları KullanmaMarshal

.NET5'ten sonra, dotnet topluluğu, koleksiyon işlemlerinin performansını artırmak için CollectionsMarshal sınıfını uyguladı. Bu sınıf, koleksiyon türlerinin yerel dizilerine nasıl erişileceğini uygular (eğer benim [. .NET Performans Optimizasyonu - Koleksiyon Türleri için Başlangıç Boyutunu Belirlemelisiniz] makalesi, birçok veri yapısının temel uygulamasının dizileri olduğunu biliyorsunuz). Böylece her türlü tespiti atlayıp doğrudan orijinal diziye erişebiliyor, ki bu en hızlı olmalı. Kod şöyle görünüyor:

Derleyici tarafından oluşturulan kodun çok verimli olduğunu görebilirsiniz.



Altta yatan diziye doğrudan erişim çok tehlikelidir, her kod satırında ne yaptığınızı bilmeli ve yeterli test yapmalısınız. Kıyaslama sonuçları aşağıdaki gibidir:



VayCollectionsMarshal'ı kullanmak, foreach kullanmaktan %79 daha hızlıdır, ama JIT optimizasyonunun sebebi olmalı, foreach ile for keyword loop Span arasında büyük bir fark yok.

özet

Bugün size Liste koleksiyonunu hızlıca nasıl geçebileceğinizi anlattım ve çoğu durumda hem taşma kontrolü hem de çok iş parçacıklı sürüm numarası kontrolü olan foreach anahtar kelimesini kullanmak öneriliyor; bu da doğru kodu yazmamızı kolaylaştırıyor.

Yüksek performans ve büyük veri hacmi istiyorsanız, koleksiyonu doğrudan CollectionsMarshal.AsSpan olarak kullanmak önerilir.

Bu makalenin kaynak kodu bağlantısı:

Bağlantı girişi görünür.

Orijinal bağlantı:Bağlantı girişi görünür.





Önceki:RabbitMQ AMQP mesaj mimarisinin ayrıntılı açıklaması
Önümüzdeki:Ağ kablosu kristal başı T568A ve T568B standardı ve farkı
2022-9-4 tarihinde yayınlandı 22:15:52 |
Öğrenmeyi öğren
2022-9-8 10:33:05 tarihinde yayınlandı |
Öğrenmeyi öğren
2023-6-27 tarihinde yayınlandı 22:39:13 |
Merhaba 12306 Bana veri içeren özel mesaj gönderebilir misiniz?
Feragatname:
Code Farmer Network tarafından yayımlanan tüm yazılım, programlama materyalleri veya makaleler yalnızca öğrenme ve araştırma amaçları içindir; Yukarıdaki içerik ticari veya yasa dışı amaçlarla kullanılamaz, aksi takdirde kullanıcılar tüm sonuçları ödemelidir. Bu sitedeki bilgiler internetten alınmakta olup, telif hakkı anlaşmazlıklarının bu siteyle hiçbir ilgisi yoktur. Yukarıdaki içeriği indirmeden sonraki 24 saat içinde bilgisayarınızdan tamamen silmelisiniz. Programı beğendiyseniz, lütfen orijinal yazılımı destekleyin, kayıt satın alın ve daha iyi orijinal hizmetler alın. Herhangi bir ihlal olursa, lütfen bizimle e-posta yoluyla iletişime geçin.

Mail To:help@itsvse.com