Opzioni di unione in PLINQ
Quando una query viene eseguita in parallelo, PLINQ esegue il partizionamento della sequenza di origine in modo che più thread possano funzionare simultaneamente su parti diverse, in genere in thread separati. Se è necessario utilizzare i risultati in un solo thread, ad esempio in un ciclo foreach (For Each in Visual Basic), i risultati di ogni thread devono essere riuniti in un'unica sequenza. Il tipo di unione eseguito da PLINQ dipende dagli operatori presenti nella query. Ad esempio, gli operatori che impongono un nuovo ordine dei risultati devono memorizzare nel buffer tutti gli elementi di tutti i thread. Dal punto di vista del thread consumer (che è anche il thread dell'utente dell'applicazione), è possibile che una query memorizzata completamente nel buffer resti in esecuzione per un notevole periodo di tempo prima di produrre il primo risultato. Altri operatori, per impostazione predefinita, vengono memorizzati nel buffer solo in parte e producono risultati in batch. L'operatore ForAll<TSource> è l'unico a non essere memorizzato nel buffer per impostazione predefinita. Produce immediatamente tutti gli elementi di tutti i thread.
Tramite il metodo WithMergeOptions<TSource>, come illustrato nell'esempio seguente, è possibile fornire a PLINQ un suggerimento che indica il tipo di unione da eseguire.
Dim scanlines = From n In nums.AsParallel().WithMergeOptions(ParallelMergeOptions.NotBuffered)
Where n Mod 2 = 0
Select ExpensiveFunc(n)
var scanLines = from n in nums.AsParallel()
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
where n % 2 == 0
select ExpensiveFunc(n);
Per l'esempio completo, vedere Procedura: specificare le opzioni di unione in PLINQ.
Se una determinata query non può supportare l'opzione richiesta, quest'ultima verrà semplicemente ignorata. Nella maggior parte dei casi non è necessario specificare un'opzione di unione per una query PLINQ. Tuttavia, in alcuni casi è possibile scoprire tramite test e misurazioni che l'esecuzione della query risulta più efficiente in una modalità non predefinita. Questa opzione viene spesso utilizzata per forzare un operatore di fusione di blocchi a eseguire lo streaming dei propri risultati allo scopo di fornire un'interfaccia utente avente una capacità di risposta maggiore.
ParallelMergeOptions
L'enumerazione ParallelMergeOptions include le opzioni seguenti che specificano, per le forme di query supportate, come viene prodotto l'output finale della query quando i risultati vengono utilizzati in un unico thread:
Not Buffered
L'opzione NotBuffered fa in modo che ogni elemento elaborato venga restituito da ogni thread appena viene prodotto. Questo comportamento è analogo a uno "streaming" dell'output. Se l'operatore AsOrdered() è presente nella query, NotBuffered conserva l'ordine degli elementi di origine. Benché quando si usa NotBuffered i risultati vengano prodotti appena sono disponibili, il tempo complessivo per produrre tutti i risultati potrebbe comunque risultare maggiore rispetto al tempo che occorrerebbe utilizzando una delle altre opzioni di unione.
Auto Buffered
Quando si utilizza l'opzione AutoBuffered la query raccoglie gli elementi in un buffer, quindi passa periodicamente il contenuto del buffer in un unico blocco al thread consumer. Questo comportamento è analogo alla produzione dei dati di origine in "blocchi" anziché mediante lo "streaming" menzionato per l'opzione NotBuffered. È possibile che AutoBuffered richieda più tempo di NotBuffered per rendere disponibile il primo elemento nel thread consumer. La dimensione del buffer e l'esatto comportamento di produzione non sono configurabili e possono variare a seconda di vari fattori correlati alla query.
FullyBuffered
Quando si utilizza l'opzione FullyBuffered non viene prodotto alcun elemento finché l'output dell'intera query non è stato memorizzato nel buffer. Benché quando si utilizza questa opzione sia possibile che occorrano tempi ancora più lunghi affinché il primo elemento sia disponibile nel thread consumer, è comunque possibile che i risultati completi vengano prodotti più velocemente rispetto a quando si utilizzano le altre opzioni.
Operatori di query che supportano le opzioni di unione
Nella tabella seguente vengono elencati gli operatori che supportano tutte le modalità delle opzioni di unione, con le limitazioni specificate.
Operatore |
Restrizioni |
---|---|
Nessuno |
|
Nessuno |
|
Solo query non ordinate che presentano un'origine di tipo Array o List. |
|
Nessuno |
|
Nessuno |
|
Solo query non ordinate che presentano un'origine di tipo Array o List. |
|
Nessuno |
|
Nessuno |
|
Nessuno |
|
Nessuno |
|
Nessuno |
Tutti gli altri operatori di query PLINQ possono ignorare le opzioni di unione fornite dall'utente. Alcuni operatori di query, ad esempio Reverse<TSource> e OrderBy, possono produrre elementi solo dopo che tutti gli elementi sono stati prodotti e riordinati. Pertanto, quando ParallelMergeOptions viene utilizzato in una query che contiene anche un operatore quale Reverse<TSource>, il comportamento dell'unione verrà applicato nella query solo dopo che tale operatore avrà prodotto i propri risultati.
La capacità di alcuni operatori di gestire le opzioni di unione dipende dal tipo della sequenza di origine e dall'eventuale uso precedente dell'operatore AsOrdered nella query. ForAll<TSource> è sempre NotBuffered. Produce immediatamente i propri elementi. OrderBy è sempre FullyBuffered. Deve ordinare l'intero elenco prima di produrre elementi.
Vedere anche
Attività
Procedura: specificare le opzioni di unione in PLINQ