Introducción a PLINQIntroduction to PLINQ

¿Qué es una consulta en paralelo?What is a Parallel Query?

Language Integrated Query (LINQ) apareció por primera vez en .NET Framework 3.5.Language-Integrated Query (LINQ) was introduced in the .NET Framework 3.5. Ofrece un modelo unificado para consultar cualquier origen de datos System.Collections.IEnumerable o System.Collections.Generic.IEnumerable<T> en un modo con seguridad de tipos.It features a unified model for querying any System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T> data source in a type-safe manner. LINQ to Objects es el nombre de las consultas LINQ que se ejecutan en colecciones en memoria, como List<T> y matrices.LINQ to Objects is the name for LINQ queries that are run against in-memory collections such as List<T> and arrays. En este artículo, se da por echo que posee un conocimiento básico de LINQ.This article assumes that you have a basic understanding of LINQ. Para obtener más información, vea Language Integrated Query (LINQ) (C#) o Language Integrated Query (LINQ) (Visual Basic).For more information, see Language-Integrated Query (LINQ) - C# or Language-Integrated Query (LINQ) - Visual Basic.

Parallel LINQ (PLINQ) es una implementación en paralelo del modelo LINQ.Parallel LINQ (PLINQ) is a parallel implementation of the LINQ pattern. En muchos sentidos, una consulta PLINQ se parece a una consulta LINQ to Objects no en paralelo.A PLINQ query in many ways resembles a non-parallel LINQ to Objects query. Las consultas PLINQ, al igual que las consultas LINQLINQ en secuencia, funcionan en cualquier origen de datos IEnumerable o IEnumerable<T> en memoria y tienen ejecución aplazada, lo que significa que no se empiezan a ejecutar hasta que se enumera la consulta.PLINQ queries, just like sequential LINQLINQ queries, operate on any in-memory IEnumerable or IEnumerable<T> data source, and have deferred execution, which means they do not begin executing until the query is enumerated. La principal diferencia es que PLINQ intenta usar completamente todos los procesadores del sistema.The primary difference is that PLINQ attempts to make full use of all the processors on the system. Para ello, crea particiones del origen de datos en segmentos y, luego, ejecuta la consulta en cada segmento en subprocesos de trabajo independientes en paralelo en varios procesadores.It does this by partitioning the data source into segments, and then executing the query on each segment on separate worker threads in parallel on multiple processors. En muchos casos, la ejecución en paralelo significa que la consulta se ejecuta considerablemente más rápido.In many cases, parallel execution means that the query runs significantly faster.

A través de la ejecución en paralelo, PLINQ puede alcanzar importantes mejoras de rendimiento con respecto al código heredado en ciertos tipos de consultas, a menudo solo con agregar la operación de consulta AsParallel al origen de datos.Through parallel execution, PLINQ can achieve significant performance improvements over legacy code for certain kinds of queries, often just by adding the AsParallel query operation to the data source. Sin embargo, el paralelismo puede presentar sus propias complejidades y no todas las operaciones de consulta se ejecutan más rápido en PLINQ.However, parallelism can introduce its own complexities, and not all query operations run faster in PLINQ. De hecho, la paralelización en realidad ralentiza ciertas consultas.In fact, parallelization actually slows down certain queries. Por lo tanto, debe entender cómo ciertos problemas, como la ordenación, afectan a las consultas en paralelo.Therefore, you should understand how issues such as ordering affect parallel queries. Para más información, consulte Introducción a la velocidad en PLINQ.For more information, see Understanding Speedup in PLINQ.

Nota

En esta documentación, se utilizan expresiones lambda para definir delegados en PLINQ.This documentation uses lambda expressions to define delegates in PLINQ. Si no está familiarizado con las expresiones lambda de C# o Visual Basic, consulte Lambda Expressions in PLINQ and TPL (Expresiones lambda en PLINQ y TPL).If you are not familiar with lambda expressions in C# or Visual Basic, see Lambda Expressions in PLINQ and TPL.

En el resto del artículo se ofrece información general de las principales clases PLINQ y se analiza cómo crear consultas PLINQ.The remainder of this article gives an overview of the main PLINQ classes, and discusses how to create PLINQ queries. Cada sección incluye vínculos a información más detallada y ejemplos de código.Each section contains links to more detailed information and code examples.

La clase ParallelEnumerableThe ParallelEnumerable Class

La clase System.Linq.ParallelEnumerable expone casi toda la funcionalidad de PLINQ.The System.Linq.ParallelEnumerable class exposes almost all of PLINQ's functionality. Junto con el resto de los tipos de espacios de nombres System.Linq, se compilan en el ensamblado System.Core.dll.It and the rest of the System.Linq namespace types are compiled into the System.Core.dll assembly. Los proyectos C# y Visual Basic predeterminados en Visual Studio hacen referencia al ensamblado e importan el espacio de nombres.The default C# and Visual Basic projects in Visual Studio both reference the assembly and import the namespace.

ParallelEnumerable incluye implementaciones de todos los operadores de consulta estándar que LINQ to Objects admite, a pesar de que no intenta ejecutar en paralelo cada uno de ellos.ParallelEnumerable includes implementations of all the standard query operators that LINQ to Objects supports, although it does not attempt to parallelize each one. Si no está familiarizado con LINQLINQ, vea los artículos sobre introducción a LINQ (C#) e introducción a LINQ (Visual Basic).If you are not familiar with LINQLINQ, see Introduction to LINQ (C#) and Introduction to LINQ (Visual Basic).

Además de los operadores de consulta estándar, la clase ParallelEnumerable contiene un conjunto de métodos que permiten comportamientos específicos de la ejecución en paralelo.In addition to the standard query operators, the ParallelEnumerable class contains a set of methods that enable behaviors specific to parallel execution. Estos métodos específicos de PLINQ se muestran en la tabla siguiente.These PLINQ-specific methods are listed in the following table.

Operador ParallelEnumerableParallelEnumerable Operator DescripciónDescription
AsParallel Punto de entrada de PLINQ.The entry point for PLINQ. Especifica que el resto de la consulta se debe ejecutar en paralelo, si es posible.Specifies that the rest of the query should be parallelized, if it is possible.
AsSequential Especifica que el resto de la consulta se debe ejecutar en secuencia, como una consulta LINQ no en paralelo.Specifies that the rest of the query should be run sequentially, as a non-parallel LINQ query.
AsOrdered Especifica que PLINQ debe conservar la ordenación de la secuencia de origen para el resto de la consulta o hasta que cambie la ordenación, por ejemplo, mediante el uso de una cláusula orderby (Order By en Visual Basic).Specifies that PLINQ should preserve the ordering of the source sequence for the rest of the query, or until the ordering is changed, for example by the use of an orderby (Order By in Visual Basic) clause.
AsUnordered Especifica que PLINQ no necesita conservar la ordenación de la secuencia de origen para el resto de la consulta.Specifies that PLINQ for the rest of the query is not required to preserve the ordering of the source sequence.
WithCancellation Especifica que PLINQ debe supervisar periódicamente el estado del token de cancelación que se proporciona y cancelar la ejecución si se solicita.Specifies that PLINQ should periodically monitor the state of the provided cancellation token and cancel execution if it is requested.
WithDegreeOfParallelism Especifica la cantidad máxima de procesadores que PLINQ debe usar para ejecutar la consulta en paralelo.Specifies the maximum number of processors that PLINQ should use to parallelize the query.
WithMergeOptions Proporciona una sugerencia sobre cómo PLINQ debería, si es posible, combinar los resultados en paralelo en una sola secuencia en el subproceso utilizado.Provides a hint about how PLINQ should, if it is possible, merge parallel results back into just one sequence on the consuming thread.
WithExecutionMode Especifica si PLINQ debe ejecutar la consulta en paralelo incluso si el comportamiento predeterminado indica que se debería ejecutar en secuencia.Specifies whether PLINQ should parallelize the query even when the default behavior would be to run it sequentially.
ForAll Método de enumeración multiproceso que, a diferencia de la iteración sobre los resultados de la consulta, permite procesar los resultados en paralelo sin tener que combinarlos primero en el subproceso del consumidor.A multithreaded enumeration method that, unlike iterating over the results of the query, enables results to be processed in parallel without first merging back to the consumer thread.
Aggregate overloadAggregate overload Sobrecarga única para PLINQ que permite la agregación inmediata sobre particiones locales de subprocesos, además de una función de agregación local para combinar los resultados de todas las particiones.An overload that is unique to PLINQ and enables intermediate aggregation over thread-local partitions, plus a final aggregation function to combine the results of all partitions.

El modelo de participaciónThe Opt-in Model

Cuando escribe una consulta, participa en PLINQ al invocar el método de extensión ParallelEnumerable.AsParallel en el origen de datos, tal como se muestra en el ejemplo siguiente.When you write a query, opt in to PLINQ by invoking the ParallelEnumerable.AsParallel extension method on the data source, as shown in the following example.

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      

El método de extensión AsParallel enlaza los operadores de consulta subsiguientes, en este caso, where y select, a las implementaciones System.Linq.ParallelEnumerable.The AsParallel extension method binds the subsequent query operators, in this case, where and select, to the System.Linq.ParallelEnumerable implementations.

Modos de ejecuciónExecution Modes

De manera predeterminada, PLINQ es conservador.By default, PLINQ is conservative. En tiempo de ejecución, la infraestructura de PLINQ analiza la estructura general de la consulta.At run time, the PLINQ infrastructure analyzes the overall structure of the query. Si existe la probabilidad de que la consulta genere aumentos de velocidad a través de la paralelización, PLINQ particiona la secuencia de origen en tareas que se pueden ejecutar en simultáneo.If the query is likely to yield speedups by parallelization, PLINQ partitions the source sequence into tasks that can be run concurrently. Si ejecutar una consulta en paralelo no es seguro, PLINQ simplemente la ejecuta en secuencia.If it is not safe to parallelize a query, PLINQ just runs the query sequentially. Si PLINQ puede elegir entre un algoritmo en paralelo posiblemente costoso y un algoritmo secuencial económico, de manera predeterminada elegirá el algoritmo secuencial.If PLINQ has a choice between a potentially expensive parallel algorithm or an inexpensive sequential algorithm, it chooses the sequential algorithm by default. Puede usar el método WithExecutionMode y la enumeración System.Linq.ParallelExecutionMode para indicar a PLINQ que seleccione el algoritmo paralelo.You can use the WithExecutionMode method and the System.Linq.ParallelExecutionMode enumeration to instruct PLINQ to select the parallel algorithm. Esto resulta útil cuando, a través de pruebas y mediciones, sabe que una consulta determinada se ejecuta más rápido en paralelo.This is useful when you know by testing and measurement that a particular query executes faster in parallel. Para obtener más información, vea Cómo: Especificar el modo de ejecución en PLINQ.For more information, see How to: Specify the Execution Mode in PLINQ.

Grado de paralelismoDegree of Parallelism

De manera predeterminada, PLINQ usa todos los procesadores del equipo host.By default, PLINQ uses all of the processors on the host computer. Puede indicar a PLINQ que use más de un número especificado de procesadores mediante el método WithDegreeOfParallelism.You can instruct PLINQ to use no more than a specified number of processors by using the WithDegreeOfParallelism method. Esto resulta útil cuando desea asegurarse de que otros procesos que estén en ejecución en el equipo reciban cierta cantidad de tiempo de CPU.This is useful when you want to make sure that other processes running on the computer receive a certain amount of CPU time. El siguiente fragmento de código limita la consulta para que solo use un máximo de dos procesadores.The following snippet limits the query to utilizing a maximum of two processors.

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

En casos en los que una consulta realiza una cantidad considerable de trabajo no enlazado a proceso, como E/S de archivo, puede se recomendable especificar un grado de paralelismo mayor que el número de núcleos de la máquina.In cases where a query is performing a significant amount of non-compute-bound work such as File I/O, it might be beneficial to specify a degree of parallelism greater than the number of cores on the machine.

Comparación entre consultas en paralelo ordenadas y no ordenadasOrdered Versus Unordered Parallel Queries

En algunas consultas, un operador de consulta debe generar resultados que conserven la ordenación de la secuencia de origen.In some queries, a query operator must produce results that preserve the ordering of the source sequence. PLINQ proporciona el operador AsOrdered para este propósito.PLINQ provides the AsOrdered operator for this purpose. AsOrdered es distinto de AsSequential.AsOrdered is distinct from AsSequential. Una secuencia AsOrdered de todos modos se procesa en paralelo, pero sus resultados se almacenan en búfer y se ordenan.An AsOrdered sequence is still processed in parallel, but its results are buffered and sorted. Dado que conservar el orden implica normalmente trabajo adicional, una secuencia AsOrdered se podría procesar más despacio que la secuencia AsUnordered predeterminada.Because order preservation typically involves extra work, an AsOrdered sequence might be processed more slowly than the default AsUnordered sequence. El hecho que una operación en paralelo ordenada determinada sea más rápida que una versión secuencial de la operación depende de muchos factores.Whether a particular ordered parallel operation is faster than a sequential version of the operation depends on many factors.

En el ejemplo de código siguiente se muestra cómo participar en conservar el orden.The following code example shows how to opt in to order preservation.

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


Para más información, consulte cómo conservar el orden en PLINQ.For more information, see Order Preservation in PLINQ.

Comparación entre consultas en paralelo y consultas secuencialesParallel vs. Sequential Queries

Algunas operaciones requieren que los datos de origen se entreguen en secuencia.Some operations require that the source data be delivered in a sequential manner. Los operadores de consulta ParallelEnumerable vuelven automáticamente al modo secuencial cuando es necesario.The ParallelEnumerable query operators revert to sequential mode automatically when it is required. Para los operadores de consulta definidos por el usuario y los delegados de usuario que requieren la ejecución secuencial, PLINQ proporciona el método AsSequential.For user-defined query operators and user delegates that require sequential execution, PLINQ provides the AsSequential method. Cuando se usa AsSequential, todos los operadores subsiguientes de la consulta se ejecutan secuencialmente hasta que se vuelve a llamar a AsParallel.When you use AsSequential, all subsequent operators in the query are executed sequentially until AsParallel is called again. Para obtener más información, vea Cómo: Combinar consultas LINQ paralelas y secuenciales.For more information, see How to: Combine Parallel and Sequential LINQ Queries.

Opciones para combinar resultados de consultaOptions for Merging Query Results

Cuando una consulta PLINQ se ejecuta en paralelo, sus resultados a partir de cada subproceso de trabajo se deben volver a combinar en el subproceso principal para que los use un bucle foreach (For Each en Visual Basic) o para su inserción en una lista o matriz.When a PLINQ query executes in parallel, its results from each worker thread must be merged back onto the main thread for consumption by a foreach loop (For Each in Visual Basic), or insertion into a list or array. En algunos casos, podría ser recomendable especificar un tipo determinado de operación Merge, por ejemplo, para comenzar a generar resultados más rápidamente.In some cases, it might be beneficial to specify a particular kind of merge operation, for example, to begin producing results more quickly. Para este propósito, PLINQ admite el método WithMergeOptions y la enumeración ParallelMergeOptions.For this purpose, PLINQ supports the WithMergeOptions method, and the ParallelMergeOptions enumeration. Para más información, consulte las opciones de combinación en PLINQ.For more information, see Merge Options in PLINQ.

El operador ForAllThe ForAll Operator

En las consultas LINQLINQ secuenciales, la ejecución se aplaza hasta que la consulta se enumera en un bucle foreach (For Each en Visual Basic) o mediante la invocación de un método como ToList, ToArray o ToDictionary.In sequential LINQLINQ queries, execution is deferred until the query is enumerated either in a foreach (For Each in Visual Basic) loop or by invoking a method such as ToList , ToArray , or ToDictionary. En PLINQ, también puede usar foreach para ejecutar la consulta e iterar a través de los resultados.In PLINQ, you can also use foreach to execute the query and iterate through the results. Sin embargo, foreach no se ejecuta en paralelo y, por lo tanto, requiere que el resultado de todas las tareas en paralelo se combinen nuevamente en el subproceso en el que se ejecuta el bucle.However, foreach itself does not run in parallel, and therefore, it requires that the output from all parallel tasks be merged back into the thread on which the loop is running. En PLINQ, puede usar foreach cuando deba conservar la ordenación final de los resultados de la consulta y también cada vez que procese los resultados de forma serial; por ejemplo, cuando llama a Console.WriteLine para cada elemento.In PLINQ, you can use foreach when you must preserve the final ordering of the query results, and also whenever you are processing the results in a serial manner, for example when you are calling Console.WriteLine for each element. Para lograr un ejecución más rápida de las consultas cuando no es necesario conservar el orden y cuando el procesamiento mismo de los resultados se puede ejecutar en paralelo, use el método ForAll para ejecutar una consulta PLINQ.For faster query execution when order preservation is not required and when the processing of the results can itself be parallelized, use the ForAll method to execute a PLINQ query. ForAll no lleva a cabo este paso de combinación final.ForAll does not perform this final merge step. En el ejemplo de código siguiente, se muestra cómo se utiliza el método ForAll.The following code example shows how to use the ForAll method. Aquí se usa System.Collections.Concurrent.ConcurrentBag<T> porque está optimizado para varios subprocesos, lo que agrega simultaneidad sin intentar quitar ningún elemento.System.Collections.Concurrent.ConcurrentBag<T> is used here because it is optimized for multiple threads adding concurrently without attempting to remove any items.

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)))

En la ilustración siguiente se muestra la diferencia entre foreach y ForAll con respecto a la ejecución de la consulta.The following illustration shows the difference between foreach and ForAll with regard to query execution.

Comparación entre ForAll y ForEachForAll vs. ForEach

CancelaciónCancellation

PLINQ se integra con los tipos de cancelación en .NET Framework 4.PLINQ is integrated with the cancellation types in .NET Framework 4. (Para más información, consulte el tema sobre la cancelación en subprocesos administrados). Por lo tanto, a diferencia de las consultas LINQ to Objects secuenciales, las consultas PLINQ se pueden cancelar.(For more information, see Cancellation in Managed Threads.) Therefore, unlike sequential LINQ to Objects queries, PLINQ queries can be canceled. Para crear una consulta PLINQ cancelable, use el operador WithCancellation en la consulta y proporcione una instancia CancellationToken como argumento.To create a cancelable PLINQ query, use the WithCancellation operator on the query and provide a CancellationToken instance as the argument. Cuando la propiedad IsCancellationRequested del token se establece en true, PLINQ lo tendrá en cuenta, detendrá el procesamiento de todos los subprocesos e iniciará OperationCanceledException.When the IsCancellationRequested property on the token is set to true, PLINQ will notice it, stop processing on all threads, and throw an OperationCanceledException.

Es posible que una consulta PLINQ siga procesando algunos elementos una vez establecido el token de cancelación.It is possible that a PLINQ query might continue to process some elements after the cancellation token is set.

Para una mayor capacidad de respuesta, también puede responder a las solicitudes de cancelación en delegados de usuario de ejecución prolongada.For greater responsiveness, you can also respond to cancellation requests in long-running user delegates. Para obtener más información, vea Cómo: Cancelar una consulta PLINQ.For more information, see How to: Cancel a PLINQ Query.

ExcepcionesExceptions

Cuando se ejecuta una consulta PLINQ, distintos subprocesos pueden generar varias excepciones de forma simultánea.When a PLINQ query executes, multiple exceptions might be thrown from different threads simultaneously. Además, el código para controlar la excepción puede estar en un subproceso distinto al del código que generó la excepción.Also, the code to handle the exception might be on a different thread than the code that threw the exception. PLINQ usa el tipo AggregateException para encapsular todas las excepciones que generó una consulta y calcular las referencias de esas excepciones nuevamente en el subproceso que realiza la llamada.PLINQ uses the AggregateException type to encapsulate all the exceptions that were thrown by a query, and marshal those exceptions back to the calling thread. En el subproceso que realiza la llamada, solo se requiere un bloque try-catch.On the calling thread, only one try-catch block is required. Sin embargo, puede iterar a través de todas las excepciones que están encapsuladas en AggregateException y capturar cualquiera desde la que pueda realizar una recuperación de forma segura.However, you can iterate through all of the exceptions that are encapsulated in the AggregateException and catch any that you can safely recover from. En raras ocasiones, se pueden generar algunas excepciones que no se ajustan en AggregateException, y ThreadAbortException tampoco se ajusta.In rare cases, some exceptions may be thrown that are not wrapped in an AggregateException, and ThreadAbortExceptions are also not wrapped.

Cuando las excepciones pueden propagarse de nuevo al subproceso de unión, es posible que una consulta continúe procesando algunos elementos después de que se haya producido la excepción.When exceptions are allowed to bubble up back to the joining thread, then it is possible that a query may continue to process some items after the exception is raised.

Para obtener más información, vea Cómo: Controlar excepciones en una consulta PLINQ.For more information, see How to: Handle Exceptions in a PLINQ Query.

Particionadores personalizadosCustom Partitioners

En algunos casos, puede mejorar el rendimiento de las consultas si escribe un particionador personalizado que aproveche algunas características de los datos de origen.In some cases, you can improve query performance by writing a custom partitioner that takes advantage of some characteristic of the source data. En la consulta, el mismo particionador personalizado es el objeto enumerable que se consulta.In the query, the custom partitioner itself is the enumerable object that is queried.

int[] arr = new int[9999];
Partitioner<int> partitioner = new MyArrayPartitioner<int>(arr);
var query = partitioner.AsParallel().Select(x => SomeFunction(x));
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 admite una cantidad fija de particiones (a pesar de que los datos se pueden reasignar de forma dinámica a esas particiones durante el tiempo de ejecución para el equilibrio de carga).PLINQ supports a fixed number of partitions (although data may be dynamically reassigned to those partitions during run time for load balancing.). For y ForEach admiten solo la partición dinámica, lo que significa que el número de particiones cambia en tiempo de ejecución.For and ForEach support only dynamic partitioning, which means that the number of partitions changes at run time. Para más información, consulte Custom Partitioners for PLINQ and TPL (Particionadores personalizados para PLINQ y TPL).For more information, see Custom Partitioners for PLINQ and TPL.

Medición del rendimiento de PLINQMeasuring PLINQ Performance

En muchos casos, una consulta se puede ejecutar en paralelo, pero la sobrecarga que implica configurar la consulta en paralelo supera el beneficio obtenido en el rendimiento.In many cases, a query can be parallelized, but the overhead of setting up the parallel query outweighs the performance benefit gained. Si una consulta no realiza mucho cálculo o si el origen de datos es pequeño, una consulta PLINQ podría ser más lenta que una consulta LINQ to Objects secuencial.If a query does not perform much computation or if the data source is small, a PLINQ query may be slower than a sequential LINQ to Objects query. Puede usar el analizador de rendimiento en paralelo en Visual Studio Team Server para comparar el rendimiento de diversas consultas, ubicar cuellos de botella en el procesamiento y determinar si la consulta se ejecuta en paralelo o secuencialmente.You can use the Parallel Performance Analyzer in Visual Studio Team Server to compare the performance of various queries, to locate processing bottlenecks, and to determine whether your query is running in parallel or sequentially. Para más información, vea Visualizador de simultaneidad y Cómo: Medir el rendimiento de consultas PLINQ.For more information, see Concurrency Visualizer and How to: Measure PLINQ Query Performance.

Vea tambiénSee also