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.
Paralel LINQ (PLINQ), Language-Integrated Sorgusu (LINQ) örüntüsünün paralel bir uygulamasıdır. PLINQ, System.Linq ad alanı için uzantı yöntemleri olarak LINQ standart sorgu işleçlerinin tam kümesini uygular ve paralel işlemler için ek işleçlere sahiptir. PLINQ, LINQ söz diziminin basitliğini ve okunabilirliğini paralel programlamanın gücüyle birleştirir.
Tavsiye
LINQ hakkında bilginiz yoksa, herhangi bir numaralandırılabilir veri kaynağını tür açısından güvenli bir şekilde sorgulamak için birleştirilmiş bir model içerir. LINQ to Objects, List<T> ve diziler gibi bellek içi koleksiyonlarda çalıştırılacak LINQ sorgularının adıdır. Bu makalede LINQ hakkında temel bilgilere sahip olduğunuz varsayılır. Daha fazla bilgi için bkz. Language-Integrated Sorgu (LINQ).
Paralel sorgu nedir?
PlINQ sorgusu birçok yönden paralel olmayan linq to Objects sorgusuna benzer. Aynı sıralı LINQ sorguları gibi, PLINQ sorguları da bellek içi IEnumerable veya IEnumerable<T> veri kaynağı üzerinde çalışır ve ertelenmiş yürütmeye sahiptir, yani sorgu numaralandırılmadıkça yürütülmeye başlamaz. Birincil fark, PLINQ'un sistemdeki tüm işlemcileri tam olarak kullanmayı denemesidir. Bunu yapmak için veri kaynağını bölümlere ayırır ve ardından sorguyu ayrı çalışan iş parçacıklarındaki her kesimde birden çok işlemci üzerinde paralel olarak yürütür. Çoğu durumda paralel yürütme, sorgunun önemli ölçüde daha hızlı çalıştığı anlamına gelir.
Paralel yürütme sayesinde PLINQ, genellikle veri kaynağına AsParallel sorgu işlemini ekleyerek belirli sorgu türleri için eski kod üzerinde önemli performans geliştirmeleri elde edebilir. Ancak paralellik kendi karmaşıklıklarına neden olabilir ve tüm sorgu işlemleri PLINQ'ta daha hızlı çalışmaz. Aslında paralelleştirme aslında bazı sorguları yavaşlatır. Bu nedenle, sıralama gibi sorunların paralel sorguları nasıl etkilediğini anlamanız gerekir. Daha fazla bilgi için bkz. PLINQ'de Hızlandırmayı Anlama .
Uyarı
Bu belgede PLINQ'ta temsilcileri tanımlamak için lambda ifadeleri kullanılır. C# veya Visual Basic'teki lambda ifadelerini bilmiyorsanız, PLINQ ve TPL'deki lambda ifadelerine ve'e bakın.
Bu makalenin geri kalanında ana PLINQ sınıflarına genel bir bakış sunulur ve PLINQ sorgularının nasıl oluşturulacağı açıklanır. Her bölüm, daha ayrıntılı bilgilerin ve kod örneklerinin bağlantılarını içerir.
ParallelEnumerable Sınıfı
System.Linq.ParallelEnumerable sınıfı, PLINQ'un neredeyse tüm işlevlerini kullanıma sunar. Bu ve System.Linq ad alanı türlerinin geri kalanı System.Core.dll derlemesinde derlenir. Visual Studio'daki varsayılan C# ve Visual Basic projeleri hem derlemeye başvurur hem de ad alanını içeri aktarır.
ParallelEnumerable, LINQ to Objects tarafından desteklenen tüm standart sorgu işleçlerinin uygulamalarını içerir, ancak her birini paralel hale getirmeyi denemez. LINQ hakkında bilginiz yoksa bkz. LINQ'ye Giriş (C#) ve LINQ'ye Giriş (Visual Basic).
Standart sorgu işleçlerine ek olarak, ParallelEnumerable sınıfı paralel yürütmeye özgü davranışları etkinleştiren bir dizi yöntem içerir. PLINQ'a özgü bu yöntemler aşağıdaki tabloda listelenmiştir.
ParallelEnumerable İşleci | Açıklama |
---|---|
AsParallel | PLINQ için giriş noktası. Mümkünse sorgunun geri kalanının paralelleştirilmesi gerektiğini belirtir. |
AsSequential | Sorgunun geri kalanının paralel olmayan bir LINQ sorgusu olarak sıralı olarak çalıştırılması gerektiğini belirtir. |
AsOrdered | PLINQ'un sorgunun geri kalanı için veya sıralama değiştirilene kadar (örneğin, bir orderby (Visual Basic'te Order By) yan tümcesi kullanarak kaynak dizisinin sıralamasını koruması gerektiğini belirtir. |
AsUnordered | Kaynak dizinin sırasını korumak için sorgunun geri kalanı için PLINQ'un gerekli olmadığını belirtir. |
WithCancellation | PLINQ'un sağlanan iptal belirtecinin durumunu düzenli aralıklarla izlemesi ve istenirse yürütmeyi iptal etmesi gerektiğini belirtir. |
WithDegreeOfParallelism | PLINQ'nin sorguyu paralelleştirmek için kullanması gereken işlemci sayısı üst sınırını belirtir. |
WithMergeOptions | PLINQ'un, mümkün olması durumunda, paralel sonuçları tüketen iş parçacığında tek bir dizide birleştirmesi gerektiğine dair bir ipucu sağlar. |
WithExecutionMode | PlINQ'un, varsayılan davranış sorguyu sırayla çalıştırmak olsa bile sorguyu paralelleştirip paralelleştirmeyeceğini belirtir. |
ForAll | Sorgunun sonuçlarını yinelemenin aksine, sonuçların ilk olarak tüketici iş parçacığına geri birleştirilmeden paralel olarak işlenmesine olanak tanıyan çok iş parçacıklı bir numaralandırma yöntemi. |
Aggregate aşırı yük | PLINQ için benzersiz olan ve iş parçacığı yerel bölümleri üzerinde ara toplam işlevine olanak tanıyan bir aşırı yükleme ve tüm bölümlerin sonuçlarını birleştirmek için son bir toplama işlevi sağlar. |
Kabul Etme Modeli
Bir sorgu yazarken, aşağıdaki örnekte gösterildiği gibi veri kaynağında ParallelEnumerable.AsParallel uzantısı yöntemini çağırarak PLINQ'u kabul edin.
var source = Enumerable.Range(1, 10000);
// Opt in to PLINQ with AsParallel.
var evenNums = from num in source.AsParallel()
where num % 2 == 0
select num;
Console.WriteLine($"{evenNums.Count()} even numbers out of {source.Count()} total");
// The example displays the following output:
// 5000 even numbers out of 10000 total
Dim source = Enumerable.Range(1, 10000)
' Opt in to PLINQ with AsParallel
Dim evenNums = From num In source.AsParallel()
Where num Mod 2 = 0
Select num
Console.WriteLine("{0} even numbers out of {1} total",
evenNums.Count(), source.Count())
' The example displays the following output:
' 5000 even numbers out of 10000 total
AsParallel uzantısı yöntemi, bu durumda where
ve select
sonraki sorgu işleçlerini System.Linq.ParallelEnumerable uygulamalarına bağlar.
Yürütme Modları
PLINQ varsayılan olarak muhafazakardır. Çalışma zamanında PLINQ altyapısı sorgunun genel yapısını analiz eder. Sorgu paralelleştirmeyle hız kazanma olasılığı yüksekse, PLINQ kaynak dizisini eşzamanlı olarak çalıştırılacak görevlere böler. Bir sorguyu paralel hale getirmek güvenli değilse PLINQ yalnızca sorguyu sıralı olarak çalıştırır. PLINQ'un pahalı olabilecek paralel algoritma ile ucuz bir sıralı algoritma arasında bir seçeneği varsa, varsayılan olarak sıralı algoritmayı seçer. PLINQ'ye paralel algoritmayı seçmesini bildirmek için WithExecutionMode yöntemini ve System.Linq.ParallelExecutionMode numaralandırmasını kullanabilirsiniz. Belirli bir sorgunun paralel olarak daha hızlı çalıştığını, test ve ölçüm yaparak öğrendiğinizde bu durum kullanışlıdır. Daha fazla bilgi için bkz. Nasıl yapılır: PLINQYürütme Modunu Belirtme.
Paralellik Derecesi
PLINQ varsayılan olarak konak bilgisayardaki tüm işlemcileri kullanır. WithDegreeOfParallelism yöntemini kullanarak PLINQ'a belirtilen sayıda işlemciden fazlasını kullanmamasını sağlayabilirsiniz. Bu, bilgisayarda çalışan diğer işlemlerin belirli bir CPU süresi aldığından emin olmak istediğinizde kullanışlıdır. Aşağıdaki kod parçacığı sorguyu en fazla iki işlemci kullanarak sınırlar.
var query = from item in source.AsParallel().WithDegreeOfParallelism(2)
where Compute(item) > 42
select item;
Dim query = From item In source.AsParallel().WithDegreeOfParallelism(2)
Where Compute(item) > 42
Select item
Bir sorgunun Dosya G/Ç gibi işlemle ilişkili olmayan önemli miktarda çalışma yaptığı durumlarda, makinedeki çekirdek sayısından daha fazla paralellik derecesi belirtmek yararlı olabilir.
Sıralı ve Sıralanmamış Paralel Sorgular
Bazı sorgularda, sorgu işlecinin kaynak dizinin sırasını koruyan sonuçlar üretmesi gerekir. PLINQ bu amaçla AsOrdered işlecini sağlar. AsOrdered AsSequentialfarklıdır. Bir AsOrdered dizisi hala paralel olarak işlenir, ancak sonuçları arabelleğe alınıp sıralanır. Sipariş koruması genellikle fazladan çalışma gerektirdiğinden, bir AsOrdered dizisi varsayılan AsUnordered dizisinden daha yavaş işlenebilir. Belirli bir sıralı paralel işlemin, işlemin sıralı sürümünden daha hızlı olup olmadığı birçok faktöre bağlıdır.
Aşağıdaki kod örneği, sipariş sırasını korumayı etkinleştirme yöntemini gösterir.
var evenNums =
from num in numbers.AsParallel().AsOrdered()
where num % 2 == 0
select num;
Dim evenNums = From num In numbers.AsParallel().AsOrdered()
Where num Mod 2 = 0
Select num
Daha fazla bilgi için bkz. PLINQ'te Sipariş Koruması.
Paralel ve Sıralı Sorgular karşılaştırması
Bazı işlemler için kaynak verilerin sıralı bir şekilde teslim edilmesi gerekir. ParallelEnumerable sorgu işleçleri gerektiğinde otomatik olarak sıralı moda geri döner. Sıralı yürütme gerektiren kullanıcı tanımlı sorgu işleçleri ve kullanıcı temsilcileri için PLINQ, AsSequential yöntemini sağlar. AsSequentialkullandığınızda, sorgudaki sonraki tüm işleçler AsParallel yeniden çağrılana kadar sırayla yürütülür. Daha fazla bilgi için bkz. Nasıl yapılır: Paralel ve Sıralı LINQ Sorgularını Birleştirme.
Sorgu Sonuçlarını Birleştirme Seçenekleri
PLINQ sorgusu paralel olarak yürütürse, her çalışan iş parçacığından elde ettiği sonuçlar, bir foreach
döngüsü (Visual Basic'teFor Each
) tarafından kullanılmak üzere ana iş parçacığına geri birleştirilmelidir ya da bir liste veya diziye eklenmelidir. Bazı durumlarda, örneğin sonuçları daha hızlı bir şekilde üretmeye başlamak için belirli bir birleştirme işlemi türünü belirtmek yararlı olabilir. Bu amaçla PLINQ, WithMergeOptions yöntemini ve ParallelMergeOptions numaralandırmasını destekler. Daha fazla bilgi için bkz. PLINQ Birleştirme Seçenekleri.
ForAll Operatörü
Sıralı LINQ sorgularında, sorgu bir foreach
(Visual Basic'teFor Each
) döngüsünde yineleme yapılana veya ToList, ToArray ya da ToDictionarygibi bir yöntem çağrılana kadar yürütme ertelenir. PLINQ'te sorguyu yürütmek ve sonuçlar arasında yineleme yapmak için foreach
de kullanabilirsiniz. Ancak, foreach
kendisi paralel olarak çalışmaz ve bu nedenle, tüm paralel görevlerden gelen çıkışın döngünün çalıştığı iş parçacığıyla yeniden birleştirilmesini gerektirir. PLINQ'te, sorgu sonuçlarının son sıralamasını korumanız gerektiğinde ve sonuçları seri bir şekilde işlerken (örneğin, her öğe için foreach
çağırırken) Console.WriteLine
kullanabilirsiniz. Sipariş koruması gerekli olmadığında ve sonuçların işlenmesi paralelleştirilebildiğinde sorgunun daha hızlı yürütülmesi için, PLINQ sorgusunu yürütmek için ForAll yöntemini kullanın.
ForAll bu son birleştirme adımlarını gerçekleştirmez. Aşağıdaki kod örneği, ForAll yönteminin nasıl kullanılacağını gösterir.
System.Collections.Concurrent.ConcurrentBag<T>, hiçbir öğeyi kaldırmaya çalışmadan eşzamanlı olarak ekleyen birden çok iş parçacığı için iyileştirildiğinden burada kullanılır.
var nums = Enumerable.Range(10, 10000);
var query =
from num in nums.AsParallel()
where num % 10 == 0
select num;
// Process the results as each thread completes
// and add them to a System.Collections.Concurrent.ConcurrentBag(Of Int)
// which can safely accept concurrent add operations
query.ForAll(e => concurrentBag.Add(Compute(e)));
Dim nums = Enumerable.Range(10, 10000)
Dim query = From num In nums.AsParallel()
Where num Mod 10 = 0
Select num
' Process the results as each thread completes
' and add them to a System.Collections.Concurrent.ConcurrentBag(Of Int)
' which can safely accept concurrent add operations
query.ForAll(Sub(e) concurrentBag.Add(Compute(e)))
Aşağıdaki çizimde sorgu yürütmeyle ilgili foreach
ile ForAll arasındaki fark gösterilmektedir.
karşılaştırması
İptal
PLINQ, .NET'teki iptal türleriyle tümleşiktir. (Daha fazla bilgi için bkz. Yönetilen İş Parçacıklarında İptal.) Bu nedenle, sıralı LINQ to Objects sorgularının aksine PLINQ sorguları iptal edilebilir. İptal edilebilir bir PLINQ sorgusu oluşturmak için sorgudaki WithCancellation işlecini kullanın ve bağımsız değişken olarak bir CancellationToken örneği sağlayın. Belirteç üzerindeki IsCancellationRequested özelliği true olarak ayarlandığında, PLINQ bunu fark eder, tüm iş parçacıklarında işlemeyi durdurur ve bir OperationCanceledExceptionoluşturur.
PLINQ sorgusu, iptal belirteci ayarlandıktan sonra bazı öğeleri işlemeye devam edebilir.
Daha fazla duyarlılık göstermek için, uzun süre çalışan kullanıcı temsilcilerindeki iptal isteklerine de yanıt verebilirsiniz. Daha fazla bilgi için bakınız: Nasıl Yapılır: PLINQ Sorgu İptal Etme.
Özel durumlar
Bir PLINQ sorgusu çalıştırıldığında, aynı anda farklı iş parçacıklarından birden çok özel durum meydana gelebilir. Ayrıca, özel durumu işlemek için kod, özel durum oluşturan koddan farklı bir iş parçacığında olabilir. PLINQ, bir sorgu tarafından oluşan tüm özel durumları kapsüllemek ve bu özel durumları çağıran iş parçacığına geri sıralamak için AggregateException türünü kullanır. Çağıran iş parçacığında sadece bir try-catch bloğu kullanmak gerekir. Ancak, AggregateException içinde kapsüllenen tüm istisnaları yineleyebilir ve güvenli bir şekilde kurtulabileceğiniz istisnaları yakalayabilirsiniz. Nadir durumlarda, AggregateExceptioniçinde sarmalanmamış bazı istisnalar atılabilir ve ThreadAbortException'ler de sarmalanmamış olarak kalır.
Özel durumların birleştirilmiş iş parçacığına geri dönmesine izin verildiğinde, bir sorgu özel durum oluşturduktan sonra bazı öğeleri işlemeye devam edebilir.
Daha fazla bilgi için, PLINQ Sorgusunda Özel Durumları Nasıl İşleyeceğinize ilişkin vebaşlıklarına bakın.
Özel Bölümleyiciler
Bazı durumlarda, kaynak verilerin bazı özelliklerinden yararlanan özel bir bölümleyici yazarak sorgu performansını geliştirebilirsiniz. Sorguda, özel bölümleyici sorgulanan numaralandırılabilir nesnedir.
int[] arr = new int[9999];
Partitioner<int> partitioner = new MyArrayPartitioner<int>(arr);
var query = partitioner.AsParallel().Select(SomeFunction);
Dim arr(10000) As Integer
Dim partitioner As Partitioner(Of Integer) = New MyArrayPartitioner(Of Integer)(arr)
Dim query = partitioner.AsParallel().Select(Function(x) SomeFunction(x))
PLINQ sabit sayıda bölümü destekler (ancak veriler yük dengeleme için çalışma zamanında bu bölümlere dinamik olarak yeniden atanabilir.). For ve ForEach yalnızca dinamik bölümleme desteği sağlar; başka bir deyişle, çalışma zamanında bölüm sayısı değişir. Daha fazla bilgi için bkz. PLINQ ve TPL için Özel Bölümleyiciler.
PLINQ Performansını Ölçme
Çoğu durumda sorgu paralelleştirilebilir, ancak paralel sorguyu ayarlamanın getirdiği ek yük, elde edilen performans avantajından daha fazladır. Sorgu çok fazla hesaplama gerçekleştirmezse veya veri kaynağı küçükse, PLINQ sorgusu sıralı LINQ to Objects sorgusundan daha yavaş olabilir. Çeşitli sorguların performansını karşılaştırmak, işleme performans sorunlarını bulmak ve sorgunuzun paralel mi yoksa sırayla mı çalıştığını belirlemek için Visual Studio Team Server'daki Paralel Performans Çözümleyicisi'ni kullanabilirsiniz. Daha fazla bilgi için bkz. Eşzamanlılık Görselleştiricisi ve Nasıl Yapılır: PLINQ Sorgu Performansını Ölçme.