PLINQ'e Giriş
Parallel LINQ (PLıNQ), dil Ile tümleşik sorgu (LINQ) deseninin paralel bir uygulamasıdır. PLıNQ, LINQ standart sorgu işleçlerinin tam kümesini ad alanı için uzantı yöntemleri olarak uygular System.Linq ve paralel işlemler için ek işleçlere sahiptir. PLıNQ, LINQ sözdiziminin basitliğini ve okunabilirliğini paralel programlama gücüyle birleştirir.
İpucu
LINQ hakkında bilgi sahibi değilseniz, bir tür açısından güvenli şekilde, sıralanabilir veri kaynaklarını sorgulamak için birleştirilmiş bir model sunar. LINQ to Objects, ve dizileri gibi bellek içi koleksiyonlara karşı çalıştırılan lınq sorgularının adıdır List<T> . Bu makalede, LINQ 'ın temel olarak anlaşıldığı varsayılmaktadır. Daha fazla bilgi için bkz. dil Ile tümleşik sorgu (LINQ).
Paralel sorgu nedir?
birçok şekilde bir plınq sorgusu, paralel olmayan LINQ to Objects sorgusuna benzer. PLıNQ sorguları, sıralı LINQ sorguları gibi tüm bellek içi IEnumerable veya IEnumerable<T> veri kaynakları üzerinde çalışır ve bu, sorgu numaralandırılana kadar yürütülmeye başlamadıkları anlamına gelir. Birincil fark, PLıNQ 'in sistemdeki tüm işlemcileri tam olarak kullanmasını denemelerinde. Bu, veri kaynağını kesimlere bölümleyerek ve sonra her kesimde sorguyu birden çok işlemci üzerinde paralel olan ayrı çalışan iş parçacıklarında yürüterek yapar. Birçok durumda, paralel yürütme sorgunun önemli ölçüde daha hızlı çalıştığı anlamına gelir.
PLıNQ, paralel yürütme sayesinde, genellikle AsParallel veri kaynağına sorgu işlemi ekleyerek, belirli türde sorgular için eski kodla önemli performans geliştirmeleri elde edebilir. Ancak paralellik, kendi karmaşıklıklarını ortaya çıkarabilir ve tüm sorgu işlemleri PLıNQ 'te daha hızlı çalışmaz. Aslında, paralelleştirme 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. PLıNQ 'Te hızlı Hızlandırlamayı anlama.
Not
Bu belgede, PLıNQ içinde temsilciler tanımlamak için lambda ifadeleri kullanılmaktadır. C# veya Visual Basic lambda ifadeleriyle ilgili bilgi sahibi değilseniz bkz. plınq ve TPL içindeki lambda ifadeleri.
Bu makalenin geri kalanı, ana PLıNQ sınıflarına genel bir bakış sağlar ve PLıNQ sorgularının nasıl oluşturulacağını açıklar. Her bölümde daha ayrıntılı bilgi ve kod örneklerine ait bağlantılar yer alır.
ParallelEnumerable Sınıfı
System.Linq.ParallelEnumerableSınıfı, neredeyse tüm PLıNQ işlevlerini gösterir. Bu ve System.Linq ad alanı türlerinin geri kalanı System.Core.dll derlemesine derlenir. Visual Studio ' deki varsayılan C# ve Visual Basic projeleri derlemeye başvurur ve ad alanını içeri aktarır.
ParallelEnumerableher birini paralel hale getirmek denemese de, LINQ to Objects desteklediği tüm standart sorgu işleçlerinin uygulamalarını içerir. LINQ hakkında bilginiz yoksa LINQ 'A giriş (C#) ve LINQ (Visual Basic) uygulamasına girişkonusuna bakın.
Standart sorgu işleçlerine ek olarak, ParallelEnumerable sınıfı paralel yürütmeye özel davranışları etkinleştiren bir yöntemler kümesi içerir. Bu PLıNQ 'e özgü yöntemler aşağıdaki tabloda listelenmiştir.
|ParallelEnumerable Işleci||Description|
|AsParallel||PLıNQ için giriş noktası. Mümkünse sorgunun geri kalanının paralelleştirilmesine sahip olması gerektiğini belirtir.|
|AsSequential||Sorgunun geri kalanının paralel olmayan bir LINQ sorgusu olarak sırayla çalıştırılması gerektiğini belirtir.|
|AsOrdered||plınq 'ın, sorgunun geri kalanı için kaynak dizinin sıralamasını korumalı veya sıralama değiştirilene kadar (örneğin, bir orderby (by Visual Basic) yan tümcesinin kullanılması gerektiğini belirtir.|
|AsUnordered||Kaynak dizinin sıralamasını korumak için sorgunun geri kalanı için PLıNQ öğesinin gerekli değildir olduğunu belirtir.|
|WithCancellation||PLıNQ 'ın, belirtilen iptal belirtecinin durumunu düzenli olarak izlemesi gerektiğini ve istenirse yürütmeyi iptal edip etmediğini belirtir.|
|WithDegreeOfParallelism||PLıNQ 'ın sorguyu paralel hale getirmek için kullanması gereken en fazla işlemci sayısını belirtir.|
|WithMergeOptions||PLıNQ 'in mümkünse, paralel sonuçları tüketim iş parçacığında yalnızca bir sırayla birleştirerek bir ipucu sağlar.|
|WithExecutionMode||Varsayılan davranış ardışık olarak çalıştırmak olduğunda bile PLıNQ 'ın sorguyu paralel hale getirmek gerekip gerekmediğini belirtir.|
|ForAll||Sorgunun sonuçlarını yinelemeden farklı olan çok iş parçacıklı numaralandırma yöntemi, önce tüketici iş parçacığına geri birleştirmeden sonuçların paralel olarak işlenmesini sağlar.|
|Aggregate yüklemek||PLıNQ için benzersiz olan ve iş parçacığı yerel bölümleri üzerinde ara toplamayı sağlayan bir aşırı yükleme ve tüm bölümlerin sonuçlarını birleştirmek için son toplama işlevi.|
Abone Olma Modeli
Bir sorgu yazdığınızda, ParallelEnumerable.AsParallel Aşağıdaki örnekte gösterildiği gibi, veri kaynağındaki genişletme yöntemini çağırarak PLINQ ' yi 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("{0} even numbers out of {1} total", evenNums.Count(), source.Count()); // 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
Yürütme Modları
Varsayılan olarak PLıNQ, koruyucu olur. Çalışma zamanında, PLıNQ altyapısı sorgunun genel yapısını analiz eder. Sorgunun paralelleştirme yoluyla hızlı hale getirme olasılığı varsa PLıNQ, kaynak dizisini aynı anda çalıştırılabilen görevlere bölümler. Bir sorgu paralel hale getirmek için güvenli değilse PLıNQ sorguyu sırayla çalıştırır. PLıNQ, potansiyel olarak pahalı bir paralel algoritma veya pahalı bir sıralı algoritma arasında seçim yaptıysanız, varsayılan olarak sıralı algoritmayı seçer. WithExecutionMode System.Linq.ParallelExecutionMode PLINQ 'in paralel algoritmayı seçmesini sağlamak için yöntemini ve sabit listesini kullanabilirsiniz. Bu, belirli bir sorgunun paralel olarak daha hızlı yürütüldüğünü test ve ölçüyle bildiğiniz durumlarda faydalıdır. Daha fazla bilgi için bkz. nasıl yapılır: PLıNQ 'Te yürütme modunu belirtme.
Paralellik Derecesi
Varsayılan olarak, PLıNQ ana bilgisayardaki tüm işlemcileri kullanır. Yöntemini kullanarak PLıNQ 'ın belirtilen sayıda işlemciyi daha fazla kullanmasını sağlayabilirsiniz WithDegreeOfParallelism . Bu, bilgisayarda çalışan diğer işlemlerin belirli bir CPU süresi miktarını aldığından emin olmak istediğinizde yararlıdır. Aşağıdaki kod parçacığı, en fazla iki işlemciyi kullanarak sorguyu sınırlandırır.
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şlem dışı bağlı önemli miktarda işi gerçekleştirdiği durumlarda, makinedeki çekirdek sayısından daha büyük bir paralellik derecesi belirtmek yararlı olabilir.
Sıralı ve Sırasız Paralel Sorgular
Bazı sorgularda, bir sorgu işleci kaynak dizinin sıralamasını koruyan sonuçlar üretmelidir. PLıNQ AsOrdered Bu amaçla operatör sağlar. AsOrdered , öğesinden farklıdır AsSequential . Bir AsOrdered dizi hala paralel olarak işlenir, ancak sonuçları arabelleğe alınır ve sıralanır. Sıra koruması genellikle ek iş içerdiğinden, bir AsOrdered sıra varsayılan sırasından daha yavaş işlenebilir AsUnordered . Belirli bir sıralı paralel işlemin, işlemin sıralı bir sürümünden daha hızlı olup olmadığı birçok faktöre bağlıdır.
Aşağıdaki kod örneğinde, siparişin korunmasını nasıl kabul edilecek gösterilmektedir.
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. PLıNQ 'Te sıra koruma.
Paralel ve sıralı sorgular
Bazı işlemler, kaynak verilerinin sıralı bir şekilde teslim edilmesini gerektirir. ParallelEnumerableSorgu işleçleri gerektiğinde otomatik olarak sıralı moda döndürülür. Kullanıcı tanımlı sorgu işleçleri ve sıralı yürütme gerektiren Kullanıcı temsilcileri için PLıNQ AsSequential yöntemi sağlar. Kullandığınızda AsSequential , sorguda sonraki tüm işleçler AsParallel tekrar çağrılıncaya 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
bir plınq sorgusu paralel olarak yürütüldüğünde, her bir çalışan iş parçacığının sonuçları bir döngüye göre tüketim
foreach (
For Each Visual Basic) veya bir liste ya da diziye ekleme için ana iş parçacığından geri birleştirilmelidir. Bazı durumlarda, örneğin, sonuçların daha hızlı bir şekilde üretilmeye başlaması gibi belirli bir birleştirme işlemi türü belirtmek yararlı olabilir. Bu amaçla PLıNQ, WithMergeOptions yöntemini ve ParallelMergeOptions sabit listesini destekler. Daha fazla bilgi için bkz. PLıNQ 'Te birleştirme seçenekleri.
ForAll İşleci
sıralı lınq sorgularında, sorgu bir
foreach (
For Each Visual Basic) döngüsünde numaralandırılıncaya veya, ya da gibi bir yöntemi çağırarak, yürütme ertelenir ToList ToArray ToDictionary . PLıNQ 'te,
foreach sorguyu yürütmek ve sonuçlar boyunca yinelemek için de kullanabilirsiniz. Ancak,
foreach kendisi paralel çalışmaz ve bu nedenle, tüm paralel görevlerden çıktının döngünün çalıştığı iş parçacığına geri birleştirilmesi gerekir. PLıNQ 'te,
foreach sorgu sonuçlarının son sıralamasını korumanız gerektiğinde ve ayrıca her bir öğe için arama yaptığınızda sonuçları seri olarak işlerken kullanabilirsiniz
Console.WriteLine . Daha hızlı sorgu yürütme sırası gerektiğinde ve sonuçların işlenmesi kendisini paralelleştirirse, ForAll BIR PLıNQ sorgusu yürütmek için yöntemini kullanın. ForAll Bu son birleştirme adımını gerçekleştirmez. Aşağıdaki kod örneği, yönteminin nasıl kullanılacağını gösterir ForAll . System.Collections.Concurrent.ConcurrentBag<T> , herhangi bir öğeyi kaldırmaya çalışmadan eşzamanlı olarak birden çok iş parçacığı eklemek 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,
foreach ForAll sorgu yürütmeyle ilgili olarak ve arasındaki fark gösterilmektedir.
İptal
PLıNQ, .NET 'teki iptal türleriyle tümleşiktir. (Daha fazla bilgi için bkz. yönetilen Iş parçacıklarında iptal.) bu nedenle, sıralı LINQ to Objects sorgularının aksine plınq sorguları iptal edilebilir. Bir iptal edilebilen PLıNQ sorgusu oluşturmak için, WithCancellation sorgudaki işleci kullanın ve CancellationToken bağımsız değişken olarak bir örnek sağlayın. IsCancellationRequestedBelirteçteki özelliği true olarak ayarlandığında PLINQ bunu fark eder, tüm iş parçacıklarında işlemeyi durdurur ve bir oluşturur OperationCanceledException .
Bir PLıNQ sorgusunun, iptal belirteci ayarlandıktan sonra bazı öğeleri işlemeye devam etmesi mümkündür.
Daha fazla yanıt verme için, uzun süre çalışan Kullanıcı Temsilcilerde iptal isteklerine de yanıt verebilirsiniz. Daha fazla bilgi için bkz. nasıl yapılır: PLıNQ sorgusunu Iptal etme.
Özel durumlar
Bir PLıNQ sorgusu yürütüldüğünde, farklı iş parçacıklarından aynı anda birden çok özel durum oluşturulabilir. Ayrıca, özel durumu işleyen kod, özel durumu oluşturan koddan farklı bir iş parçacığında olabilir. PLıNQ, AggregateException bir sorgu tarafından oluşturulan tüm özel durumları kapsüllemek ve bu özel durumları çağıran iş parçacığına geri sıralamak için türünü kullanır. Çağıran iş parçacığında yalnızca bir try-catch bloğu gereklidir. Bununla birlikte, içinde kapsüllenmiş tüm özel durumlar boyunca yineleyebilir AggregateException ve güvenle kurtarabileceğiniz her türlü özel durumu yakalayın. Nadiren de olsa, bazı özel durumlar, bir içinde sarmalanmamış AggregateException ve ThreadAbortException öğeleri sarmalanmamış olabilir.
Özel durumların katılan iş parçacığına balon ekleme yapmasına izin verildiğinde, bir sorgu özel durum oluşturulduktan sonra bazı öğeleri işlemeye devam edebilir.
Daha fazla bilgi için bkz. nasıl yapılır: PLıNQ sorgusunda özel durumları işleme.
Özel Bölümleyiciler
Bazı durumlarda, kaynak verilerinin bazı özelliklerden yararlanan özel bir bölümleyici yazarak sorgu performansını artırabilirsiniz. Sorguda, özel bölümleyici, sorgulanan sıralanabilir 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))
PLıNQ, sabit sayıda bölümü destekler (ancak, veriler yük dengeleme için çalışma süresi boyunca dinamik olarak bu bölümlere yeniden atanabilir.). For ve ForEach yalnızca dinamik Bölümlendirmeyi destekler, bu da çalışma zamanında bölüm sayısının değiştiği anlamına gelir. Daha fazla bilgi için bkz. PLıNQ ve TPL Için Özel Bölümleyiciler.
PLINQ Performansını Ölçme
Birçok durumda, bir sorgu paralellik olabilir, ancak paralel sorgu ayarlama yükü, kazanılan performans avantajını ortadan kaldırır. bir sorgu çok fazla hesaplama gerçekleştirmezse veya veri kaynağı küçükse, bir plınq sorgusu sıralı bir LINQ to Objects sorgusundan daha yavaş olabilir. çeşitli sorguların performansını karşılaştırmak, işleme sorunlarını gidermek ve sorgunuzun paralel veya sıralı olarak çalışıp çalışmadığı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.