Informazioni sull'aumento di velocità in PLINQUnderstanding Speedup in PLINQ

L'obiettivo principale di PLINQ consiste nel velocizzare l'esecuzione di query LINQ to Objects mediante l'esecuzione di delegati di query in parallelo in computer multicore.The primary purpose of PLINQ is to speed up the execution of LINQ to Objects queries by executing the query delegates in parallel on multi-core computers. PLINQ assicura le prestazioni migliori quando l'elaborazione di ogni elemento in una raccolta di origine è indipendente, senza stati condivisi tra i singoli delegati.PLINQ performs best when the processing of each element in a source collection is independent, with no shared state involved among the individual delegates. Tali operazioni sono comuni in LINQ to Objects e PLINQ e spesso vengono definite "squisitamente parallele" perché si prestano facilmente alla pianificazione su più thread.Such operations are common in LINQ to Objects and PLINQ, and are often called "delightfully parallel" because they lend themselves easily to scheduling on multiple threads. Tuttavia, non tutte le query sono costituite interamente da operazioni squisitamente parallele. Nella maggior parte dei casi una query implica alcuni operatori che non possono essere parallelizzati o che rallentano l'esecuzione parallela.However, not all queries consist entirely of delightfully parallel operations; in most cases, a query involves some operators that either cannot be parallelized, or that slow down parallel execution. Anche in caso di query che sono tutte squisitamente parallele, PLINQ deve comunque partizionare l'origine dati e pianificare il lavoro sui thread, unendo in genere i risultati al termine della query.And even with queries that are entirely delightfully parallel, PLINQ must still partition the data source and schedule the work on the threads, and usually merge the results when the query completes. Tutte queste operazioni incrementano i costi di calcolo della parallelizzazione, che vengono definiti sovraccarico.All these operations add to the computational cost of parallelization; these costs of adding parallelization are called overhead. Per ottenere prestazioni ottimali in una query PLINQ, l'obiettivo è ottimizzare le parti squisitamente parallele e ridurre al minimo quelle che comportano un sovraccarico.To achieve optimum performance in a PLINQ query, the goal is to maximize the parts that are delightfully parallel and minimize the parts that require overhead. Questo articolo fornisce informazioni che consentono di scrivere query PLINQ che siano il più efficaci possibile producendo comunque risultati corretti.This article provides information that will help you write PLINQ queries that are as efficient as possible while still yielding correct results.

Fattori che influiscono sulle prestazioni delle query PLINQFactors that Impact PLINQ Query Performance

Nelle sezioni successive sono elencati alcuni dei fattori più importanti che influiscono sulle prestazioni delle query parallele.The following sections lists some of the most important factors that impact parallel query performance. Si tratta di istruzioni generali che da sole non sono sufficienti per stimare le prestazioni delle query in tutti i casi.These are general statements that by themselves are not sufficient to predict query performance in all cases. Come sempre, è importante misurare le prestazioni effettive di query specifiche in computer con una gamma di configurazioni e carichi rappresentativi.As always, it is important to measure actual performance of specific queries on computers with a range of representative configurations and loads.

  1. Costo di calcolo del lavoro complessivo.Computational cost of the overall work.

    Per ottenere un aumento della velocità, una query PLINQ deve avere abbastanza lavoro squisitamente parallelo da compensare il sovraccarico.To achieve speedup, a PLINQ query must have enough delightfully parallel work to offset the overhead. Il lavoro può essere espresso come il costo di calcolo di ogni delegato moltiplicato per il numero di elementi nella raccolta di origine.The work can be expressed as the computational cost of each delegate multiplied by the number of elements in the source collection. Supponendo che un'operazione possa essere parallelizzata, quanto più è onerosa dal punto di vista del calcolo, maggiore sarà la possibilità di aumento della velocità.Assuming that an operation can be parallelized, the more computationally expensive it is, the greater the opportunity for speedup. Ad esempio, se una funzione impiega un millisecondo per essere eseguita, una query sequenziale su 1000 elementi richiederà un secondo per eseguire questa operazione, mentre una query parallela in un computer con quattro core potrebbe richiedere solo 250 millisecondi.For example, if a function takes one millisecond to execute, a sequential query over 1000 elements will take one second to perform that operation, whereas a parallel query on a computer with four cores might take only 250 milliseconds. Il risultato è un aumento della velocità di 750 millisecondi.This yields a speedup of 750 milliseconds. Se la funzione impiega un secondo per essere eseguita per ogni elemento, l'aumento della velocità potrebbe essere di 750 secondi.If the function required one second to execute for each element, then the speedup would be 750 seconds. Se il delegato è molto costoso, PLINQ potrebbe assicurare un aumento della velocità significativo con solo alcuni elementi nella raccolta di origine.If the delegate is very expensive, then PLINQ might offer significant speedup with only a few items in the source collection. Al contrario, le raccolte di origine di dimensioni ridotte con delegati semplici non costituiscono in genere una scelta valida per PLINQ.Conversely, small source collections with trivial delegates are generally not good candidates for PLINQ.

    Nell'esempio seguente la queryA è con buone probabilità un candidato valido per PLINQ, presupponendo che la funzione Select comporti molto lavoro.In the following example, queryA is probably a good candidate for PLINQ, assuming that its Select function involves a lot of work. È probabile invece che la queryB non sia un candidato valido, in quanto nell'istruzione Select non è presente un volume di lavoro sufficiente e il sovraccarico della parallelizzazione compenserà interamente o in buona parte l'aumento di velocità.queryB is probably not a good candidate because there is not enough work in the Select statement, and the overhead of parallelization will offset most or all of the speedup.

    Dim queryA = From num In numberList.AsParallel()  
                 Select ExpensiveFunction(num); 'good for PLINQ  
    
    Dim queryB = From num In numberList.AsParallel()  
                 Where num Mod 2 > 0  
                 Select num; 'not as good for PLINQ  
    
    var queryA = from num in numberList.AsParallel()  
                 select ExpensiveFunction(num); //good for PLINQ  
    
    var queryB = from num in numberList.AsParallel()  
                 where num % 2 > 0  
                 select num; //not as good for PLINQ  
    
  2. Numero di core logici nel sistema (grado di parallelismo).The number of logical cores on the system (degree of parallelism).

    Questo punto è un ovvio corollario della sezione precedente. Le query squisitamente parallele vengono eseguite più velocemente nei computer con più core perché il lavoro può essere suddiviso tra più thread simultanei.This point is an obvious corollary to the previous section, queries that are delightfully parallel run faster on machines with more cores because the work can be divided among more concurrent threads. L'aumento di velocità totale dipende dalla percentuale di lavoro complessivo della query parallelizzabile.The overall amount of speedup depends on what percentage of the overall work of the query is parallelizable. Tuttavia, non bisogna partire dal presupposto che tutte le query verranno eseguite a velocità raddoppiata in un computer con otto core rispetto a uno con quattro core.However, do not assume that all queries will run twice as fast on an eight core computer as a four core computer. In fase di ottimizzazione delle query per ottenere prestazioni di livello più elevato, è importante misurare i risultati effettivi nei computer con diversi numeri di core.When tuning queries for optimal performance, it is important to measure actual results on computers with various numbers of cores. Questo punto è strettamente correlato al primo: sono richiesti set di dati più grandi per sfruttare i vantaggi offerti da maggiori risorse di elaborazione.This point is related to point #1: larger datasets are required to take advantage of greater computing resources.

  3. Numero e tipo di operazioni.The number and kind of operations.

    PLINQ fornisce l'operatore AsOrdered per situazioni in cui è necessario mantenere l'ordine degli elementi nella sequenza di origine.PLINQ provides the AsOrdered operator for situations in which it is necessary to maintain the order of elements in the source sequence. L'ordinamento prevede un costo, che tuttavia è in genere limitato.There is a cost associated with ordering, but this cost is usually modest. Anche GroupBy e le operazioni di join comportano un sovraccarico.GroupBy and Join operations likewise incur overhead. PLINQ assicura le prestazioni migliori quando è consentito elaborare gli elementi nella raccolta di origine in qualsiasi ordine e passarli all'operatore successivo non appena sono pronti.PLINQ performs best when it is allowed to process elements in the source collection in any order, and pass them to the next operator as soon as they are ready. Per altre informazioni, vedere Conservazione dell'ordine in PLINQ.For more information, see Order Preservation in PLINQ.

  4. Formato di esecuzione della query.The form of query execution.

    Se si archiviano i risultati di una query chiamando ToArray o ToList, i risultati di tutti i thread paralleli devono essere uniti in un'unica struttura di dati.If you are storing the results of a query by calling ToArray or ToList, then the results from all parallel threads must be merged into the single data structure. Ciò comporta un costo di calcolo inevitabile.This involves an unavoidable computational cost. Analogamente, se si scorrono i risultati usando un ciclo foreach (For Each in Visual Basic), i risultati dei thread di lavoro devono essere serializzati sul thread dell'enumeratore.Likewise, if you iterate the results by using a foreach (For Each in Visual Basic) loop, the results from the worker threads need to be serialized onto the enumerator thread. Ma se si vogliono semplicemente eseguire operazioni basate sul risultato di ogni thread, è possibile usare il metodo ForAll per eseguire questa attività su più thread.But if you just want to perform some action based on the result from each thread, you can use the ForAll method to perform this work on multiple threads.

  5. Tipo di opzioni di unione.The type of merge options.

    PLINQ può essere configurato per il buffering dell'output e la relativa visualizzazione in blocchi o tutto in una volta dopo che è stato prodotto l'intero set di risultati oppure per lo streaming dei singoli risultati mano a mano che vengono prodotti.PLINQ can be configured to either buffer its output, and produce it in chunks or all at once after the entire result set is produced, or else to stream individual results as they are produced. Nel primo caso il tempo di esecuzione complessivo diminuisce, mentre nel secondo il risultato è una riduzione della latenza tra gli elementi restituiti.The former result is decreased overall execution time and the latter results in decreased latency between yielded elements. Mentre le opzioni di unione non hanno sempre un impatto significativo sulle prestazioni complessive delle query, possono incidere sulle prestazioni percepite dal momento che controllano quanto tempo deve attendere un utente per vedere i risultati.While the merge options do not always have a major impact on overall query performance, they can impact perceived performance because they control how long a user must wait to see results. Per altre informazioni, vedere Opzioni di unione in PLINQ.For more information, see Merge Options in PLINQ.

  6. Tipo di partizionamento.The kind of partitioning.

    In alcuni casi una query PLINQ su una raccolta di origine indicizzabile può comportare un carico di lavoro non equilibrato.In some cases, a PLINQ query over an indexable source collection may result in an unbalanced work load. Quando ciò si verifica, potrebbe essere possibile aumentare le prestazioni delle query creando un partitioner personalizzato.When this occurs, you might be able to increase the query performance by creating a custom partitioner. Per altre informazioni, vedere Partitioner personalizzati per PLINQ e TPL.For more information, see Custom Partitioners for PLINQ and TPL.

Quando PLINQ sceglie la modalità sequenzialeWhen PLINQ Chooses Sequential Mode

PLINQ tenterà sempre di eseguire una query almeno alla stessa velocità con cui la query verrebbe eseguita in sequenza.PLINQ will always attempt to execute a query at least as fast as the query would run sequentially. Anche se PLINQ non prende in considerazione il costo dei delegati dell'utente dal punto di vista del calcolo o la grandezza dell'origine di input, presta attenzione a determinate "forme" delle query.Although PLINQ does not look at how computationally expensive the user delegates are, or how big the input source is, it does look for certain query "shapes." In particolare, prende in considerazione operatori di query o combinazioni di operatori che possono rallentare l'esecuzione di una query in modalità parallela.Specifically, it looks for query operators or combinations of operators that typically cause a query to execute more slowly in parallel mode. Quando vengono individuate tali forme, per impostazione predefinita PLINQ torna alla modalità sequenziale.When it finds such shapes, PLINQ by default falls back to sequential mode.

Tuttavia, dopo avere misurato le prestazioni di una query specifica, è possibile determinare che viene effettivamente eseguita più velocemente in modalità parallela.However, after measuring a specific query's performance, you may determine that it actually runs faster in parallel mode. In questi casi è possibile usare il flag ParallelExecutionMode.ForceParallelism tramite il metodo WithExecutionMode per indicare a PLINQ di parallelizzare la query.In such cases you can use the ParallelExecutionMode.ForceParallelism flag via the WithExecutionMode method to instruct PLINQ to parallelize the query. Per altre informazioni, vedere Procedura: Specificare la modalità di esecuzione in PLINQ.For more information, see How to: Specify the Execution Mode in PLINQ.

Nell'elenco seguente sono riportate le forme delle query che per impostazione predefinita PLINQ eseguirà in modalità sequenziale:The following list describes the query shapes that PLINQ by default will execute in sequential mode:

  • Query che contengono una clausola Select, una clausola Where indicizzata, una clausola SelectMany indicizzata o una clausola ElementAt dopo un operatore di ordinamento o di filtro che ha rimosso o riorganizzato gli indici originali.Queries that contain a Select, indexed Where, indexed SelectMany, or ElementAt clause after an ordering or filtering operator that has removed or rearranged original indices.

  • Query che contengono un operatore Take, TakeWhile, Skip, SkipWhile e in cui gli indici nella sequenza di origine non sono nell'ordine originale.Queries that contain a Take, TakeWhile, Skip, SkipWhile operator and where indices in the source sequence are not in the original order.

  • Query che contengono Zip o SequenceEquals, a meno che in una delle origini dati non sia presente un indice originariamente ordinato e l'altra origine dati non sia indicizzabile (ad esempio un array o IList(T)).Queries that contain Zip or SequenceEquals, unless one of the data sources has an originally ordered index and the other data source is indexable (i.e. an array or IList(T)).

  • Query che contengono Concat, a meno che non sia applicato a origini dati indicizzabili.Queries that contain Concat, unless it is applied to indexable data sources.

  • Query che contengono Reverse, a meno che non sia applicato a un'origine dati indicizzabile.Queries that contain Reverse, unless applied to an indexable data source.

Vedere ancheSee Also

Parallel LINQ (PLINQ)Parallel LINQ (PLINQ)