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.
Çoğu durumda PLINQ, sıralı LINQ to Objects sorgularına göre önemli performans geliştirmeleri sağlayabilir. Ancak, sorgu yürütmesini paralelleştirme çalışması, sıralı kodda o kadar yaygın olmayan veya hiç karşılaşmayan sorunlara yol açabilecek karmaşıklığa neden olabilir. Bu konuda, PLINQ sorguları yazarken kaçınılması gereken bazı yöntemler listelenir.
Paralelin her zaman daha hızlı olduğunu varsaymayın
Paralelleştirme bazen PLINQ sorgularının LINQ to Objects eşdeğerinden daha yavaş çalışmasına neden olur. Temel kural, birkaç kaynak öğeye ve hızlı kullanıcı temsilcilerine sahip sorguların çok fazla hızlanma olasılığının düşük olmasıdır. Ancak, performansa birçok faktör dahil olduğundan, PLINQ kullanıp kullanmamaya karar vermeden önce gerçek sonuçları ölçmenizi öneririz. Daha fazla bilgi için bkz. PLINQ'de Hızlandırmayı Anlama .
Paylaşılan bellek konumlarına yazmaktan kaçının
Sıralı kodda, statik değişkenlerden veya sınıf alanlarından okuma veya yazma işlemi sık karşılaşılan bir durum değildir. Ancak, bu tür değişkenlere aynı anda birden çok iş parçacığı eriştiğinde, yarış koşullarının oluşma olasılığı yüksektir. Değişkene erişimi eşitlemek için kilitleri kullanabilirsiniz, ancak eşitlemenin maliyeti performansı etkileyebilir. Bu nedenle, PLINQ sorgusunda paylaşılan duruma erişimi mümkün olduğunca engellemenizi veya en azından sınırlamanızı öneririz.
Fazla paralelleştirmeden kaçının
AsParallel yöntemini kullanarak kaynak koleksiyonunu bölümlemenin ve çalışan iş parçacıklarını eşitlemenin ek yük maliyetlerine katlanırsınız. Paralelleştirmenin avantajları, bilgisayardaki işlemci sayısıyla daha da sınırlıdır. Yalnızca bir işlemcide birden çok işlem ilişkili iş parçacığı çalıştırılarak kazanılacak bir hız yoktur. Bu nedenle, bir sorguyu fazla paralelleştirmemeye dikkat etmeniz gerekir.
Aşırı paralelleştirmenin gerçekleşebildiği en yaygın senaryo, aşağıdaki kod parçacığında gösterildiği gibi iç içe geçmiş sorgulardadır.
var q = from cust in customers.AsParallel()
from order in cust.Orders.AsParallel()
where order.OrderDate > date
select new { cust, order };
Dim q = From cust In customers.AsParallel()
From order In cust.Orders.AsParallel()
Where order.OrderDate > aDate
Select New With {cust, order}
Bu durumda, aşağıdaki koşullardan biri veya daha fazlası geçerli olmadıkça yalnızca dış veri kaynağını (müşteriler) paralel hale getirmek en iyisidir:
Dahili veri kaynağı (cust.Orders) çok uzun olduğu bilinir.
Her siparişte pahalı bir hesaplama gerçekleştiriyorsunuz. (Örnekte gösterilen işlem pahalı değildir.)
Hedef sistemin üzerinde sorgu
cust.Ordersparalelleştirilerek oluşturulacak iş parçacığı sayısını işlemek için yeterli işlemciye sahip olduğu bilinmektedir.
Her durumda, en uygun sorgu şeklini belirlemenin en iyi yolu test etmek ve ölçmektir. Daha fazla bilgi için bkz . Nasıl yapılır: PLINQ Sorgu Performansını Ölçme.
İş parçacığı güvenli olmayan yöntemlere yapılan çağrılardan kaçının
Bir PLINQ sorgusundan iş parçacığı güvenli olmayan örnek yöntemlerine yazmak, programınızda algılanabilir veya algılanamayacak veri bozulmasına neden olabilir. Ayrıca özel durumlara yol açabilir. Aşağıdaki örnekte, sınıf tarafından desteklenmeyen FileStream.Write yöntemini aynı anda birden çok iş parçacığı çağırmaya çalışacaktır.
Dim fs As FileStream = File.OpenWrite(…)
a.AsParallel().Where(...).OrderBy(...).Select(...).ForAll(Sub(x) fs.Write(x))
FileStream fs = File.OpenWrite(...);
a.AsParallel().Where(...).OrderBy(...).Select(...).ForAll(x => fs.Write(x));
İş parçacığı güvenli yöntemlere yapılan çağrıları sınırla
.NET'teki çoğu statik yöntem iş parçacığı açısından güvenlidir ve aynı anda birden çok iş parçacığından çağrılabilir. Ancak bu durumlarda bile, söz konusu eşitleme sorguda önemli bir yavaşlamayla sonuçlanabilir.
Uyarı
Bunu kendiniz test etmek için sorgularınıza WriteLine çağrıları ekleyebilirsiniz. Bu yöntem, belge örneklerinde tanıtım amacıyla kullanılsa da PLINQ sorgularında kullanmayın.
Gereksiz sıralama işlemlerinden kaçının
PLINQ bir sorguyu paralel olarak yürüttüğünde, kaynak diziyi birden çok iş parçacığında eşzamanlı olarak çalıştırılabilir bölümlere böler. Varsayılan olarak, bölümlerin işlenme ve sonuçların teslim edilme sırası tahmin edilebilir değildir (gibi OrderByişleçler hariç). PLINQ'a herhangi bir kaynak dizisinin sırasını korumasını sağlayabilirsiniz, ancak bunun performans üzerinde olumsuz bir etkisi vardır. Mümkün olduğunda en iyi yöntem, sorguları düzen korumasına güvenmemeleri için yapılandırmaktır. Daha fazla bilgi için bkz. PLINQ'te Sipariş Koruması.
Mümkün olduğunda ForEach için ForAll'ı tercih edin
PLINQ bir sorguyu birden çok iş parçacığında yürütse de, sonuçları bir foreach döngüde (For Each Visual Basic'te) tüketirseniz, sorgu sonuçları bir iş parçacığında birleştirilmeli ve numaralandırıcı tarafından seri olarak erişilmelidir. Bazı durumlarda kaçınılmazdır, ancak mümkün olduğunda her iş parçacığının kendi sonuçlarını yazabilmesi için ForAll yöntemini kullanın; örneğin, System.Collections.Concurrent.ConcurrentBag<T> gibi iş parçacığı güvenli bir koleksiyona yazarak.
Aynı sorun için Parallel.ForEachde geçerlidir. Başka bir deyişle, source.AsParallel().Where().ForAll(...) kesinlikle Parallel.ForEach(source.AsParallel().Where(), ...) yerine tercih edilmelidir.
İş parçacığı bağlılık sorunlarına dikkat edin
Tek İş Parçacıklı Daire (STA) bileşenleri, Windows Forms ve Windows Presentation Foundation (WPF) için COM birlikte çalışabilirliği gibi bazı teknolojiler, kodun belirli bir iş parçacığında çalıştırılmasını gerektiren iş parçacığı benşimi kısıtlamaları uygular. Örneğin, hem Windows Forms hem de WPF'de denetime yalnızca oluşturulduğu iş parçacığında erişilebilir. PLINQ sorgusunda Windows Forms denetiminin paylaşılan durumuna erişmeye çalışırsanız, hata ayıklayıcıda çalışıyorsanız bir özel durum oluşur. (Bu ayar kapatılabilir.) Ancak, sorgunuz UI iş parçacığında tüketiliyorsa, bu kod yalnızca bir iş parçacığında yürütüldüğü için sorgu sonuçlarını numaralandıran döngüden kontrole erişebilirsiniz.
ForEach, For ve ForAll yinelemelerinin her zaman paralel olarak yürütüldüğünü varsaymayın
Parallel.For, Parallel.ForEach veya ForAll döngüsündeki bireysel yinelemelerin paralel olarak yürütülmesi mümkün olmakla birlikte, zorunlu değildir; bunu akılda tutmak önemlidir. Bu nedenle, yinelemelerin paralel yürütülmesine veya yinelemelerin belirli bir sırada yürütülmesine doğruluğa bağlı olan herhangi bir kod yazmaktan kaçınmanız gerekir.
Örneğin, bu kodun kilitlenme olasılığı yüksektir:
Dim mre = New ManualResetEventSlim()
Enumerable.Range(0, Environment.ProcessorCount * 100).AsParallel().ForAll(Sub(j)
If j = Environment.ProcessorCount Then
Console.WriteLine("Set on {0} with value of {1}", Thread.CurrentThread.ManagedThreadId, j)
mre.Set()
Else
Console.WriteLine("Waiting on {0} with value of {1}", Thread.CurrentThread.ManagedThreadId, j)
mre.Wait()
End If
End Sub) ' deadlocks
ManualResetEventSlim mre = new ManualResetEventSlim();
Enumerable.Range(0, Environment.ProcessorCount * 100).AsParallel().ForAll((j) =>
{
if (j == Environment.ProcessorCount)
{
Console.WriteLine("Set on {0} with value of {1}", Thread.CurrentThread.ManagedThreadId, j);
mre.Set();
}
else
{
Console.WriteLine("Waiting on {0} with value of {1}", Thread.CurrentThread.ManagedThreadId, j);
mre.Wait();
}
}); //deadlocks
Bu örnekte, bir yineleme bir olayı ayarlar ve diğer tüm yinelemeler olay üzerinde bekler. Olay ayarı yinelemesi tamamlanana kadar bekleyen yinelemelerin hiçbiri tamamlanamaz. Ancak, olay tetikleme yinelemesi henüz yürütülme şansı bulamadan önce, bekleyen yinelemelerin, paralel döngüyü yürütmekte kullanılan tüm iş parçacıklarını durdurması mümkündür. Bu bir çıkmaza neden olur; olay oluşturma yinelemesi hiçbir zaman yürütülmeyecek ve bekleyen yinelemeler hiçbir zaman uyanmayacaktır.
Özellikle, paralel döngünün bir yinelemesi hiçbir zaman ilerleme kaydetmek için döngünün başka bir yinelemesini beklememelidir. Paralel döngü yinelemeleri sıralı olarak ancak ters sırada zamanlamaya karar verirse bir kilitlenme oluşur.