Procedura: controllare l'ordine in una query PLINQ

Questi esempi mostrano come controllare l'ordinamento in una query PLINQ usando il metodo di estensione AsOrdered.

Avviso

Lo scopo di questi esempi consiste principalmente nel mostrare l'utilizzo e la loro esecuzione potrebbe non essere più rapida delle query LINQ to Objects sequenziali equivalenti.

Esempio 1

L'esempio seguente mantiene l'ordinamento della sequenza di origine. Questo comportamento è talvolta necessario. Ad esempio, alcuni operatori di query richiedono una sequenza di origine ordinata per produrre risultati corretti.

var source = Enumerable.Range(9, 10000);

// Source is ordered; let's preserve it.
var parallelQuery =
    from num in source.AsParallel().AsOrdered()
    where num % 3 == 0
    select num;

// Use foreach to preserve order at execution time.
foreach (var item in parallelQuery)
{
    Console.Write($"{item} ");
}

// Some operators expect an ordered source sequence.
var lowValues = parallelQuery.Take(10);
Sub OrderedQuery()

    Dim source = Enumerable.Range(9, 10000)

    ' Source is ordered let's preserve it.
    Dim parallelQuery = From num In source.AsParallel().AsOrdered()
                        Where num Mod 3 = 0
                        Select num

    ' Use For Each to preserve order at execution time.
    For Each item In parallelQuery
        Console.Write("{0} ", item)
    Next

    ' Some operators expect an ordered source sequence.
    Dim lowValues = parallelQuery.Take(10)

End Sub

Esempio 2

L'esempio seguente mostra alcuni operatori di query la cui sequenza di origine sarà probabilmente ordinata. Questi operatori funzioneranno in sequenze non ordinate, ma possono produrre risultati imprevisti.

// Paste into PLINQDataSample class.
static void SimpleOrdering()
{

    var customers = GetCustomers();

    // Take the first 20, preserving the original order
    var firstTwentyCustomers = customers
                                .AsParallel()
                                .AsOrdered()
                                .Take(20);

    foreach (var c in firstTwentyCustomers)
        Console.Write("{0} ", c.CustomerID);

    // All elements in reverse order.
    var reverseOrder = customers
                        .AsParallel()
                        .AsOrdered()
                        .Reverse();

    foreach (var v in reverseOrder)
        Console.Write("{0} ", v.CustomerID);

    // Get the element at a specified index.
    var cust = customers.AsParallel()
                        .AsOrdered()
                        .ElementAt(48);

    Console.WriteLine("Element #48 is: {0}", cust.CustomerID);
}
' Paste into PLINQDataSample class
Shared Sub SimpleOrdering()
    Dim customers As List(Of Customer) = GetCustomers().ToList()

    ' Take the first 20, preserving the original order

    Dim firstTwentyCustomers = customers _
                                .AsParallel() _
                                .AsOrdered() _
                                .Take(20)

    Console.WriteLine("Take the first 20 in original order")
    For Each c As Customer In firstTwentyCustomers
        Console.Write(c.CustomerID & " ")
    Next

    ' All elements in reverse order.
    Dim reverseOrder = customers _
                        .AsParallel() _
                        .AsOrdered() _
                        .Reverse()

    Console.WriteLine(vbCrLf & "Take all elements in reverse order")
    For Each c As Customer In reverseOrder
        Console.Write("{0} ", c.CustomerID)
    Next
    ' Get the element at a specified index. 
    Dim cust = customers.AsParallel() _
                        .AsOrdered() _
                        .ElementAt(48)

    Console.WriteLine("Element #48 is: " & cust.CustomerID)

End Sub

Per eseguire questo metodo, incollarlo nella classe PLINQDataSample nel progetto PLINQ Data Sample e premere F5.

Esempio 3

L'esempio seguente mostra come mantenere l'ordinamento per la prima parte di una query, rimuovere l'ordinamento per migliorare le prestazioni di una clausola join e quindi riapplicare l'ordinamento alla sequenza di risultati finale.

// Paste into PLINQDataSample class.
static void OrderedThenUnordered()
{

    var orders = GetOrders();
    var orderDetails = GetOrderDetails();

    var q2 = orders.AsParallel()
       .Where(o => o.OrderDate < DateTime.Parse("07/04/1997"))
       .Select(o => o)
       .OrderBy(o => o.CustomerID) // Preserve original ordering for Take operation.
       .Take(20)
       .AsUnordered()  // Remove ordering constraint to make join faster.
       .Join(
              orderDetails.AsParallel(),
              ord => ord.OrderID,
              od => od.OrderID,
              (ord, od) =>
              new
              {
                  ID = ord.OrderID,
                  Customer = ord.CustomerID,
                  Product = od.ProductID
              }
             )
       .OrderBy(i => i.Product); // Apply new ordering to final result sequence.

    foreach (var v in q2)
        Console.WriteLine("{0} {1} {2}", v.ID, v.Customer, v.Product);
}
' Paste into PLINQDataSample class
Sub OrderedThenUnordered()
    Dim Orders As IEnumerable(Of Order) = GetOrders()
    Dim orderDetails As IEnumerable(Of OrderDetail) = GetOrderDetails()

    ' Sometimes it's easier to create a query
    ' by composing two subqueries
    Dim query1 = From ord In Orders.AsParallel()
                 Where ord.OrderDate < DateTime.Parse("07/04/1997")
                 Select ord
                 Order By ord.CustomerID
                 Take 20

    Dim query2 = From ord In query1.AsUnordered()
                 Join od In orderDetails.AsParallel() On ord.OrderID Equals od.OrderID
                 Order By od.ProductID
                 Select New With {ord.OrderID, ord.CustomerID, od.ProductID}


    For Each item In query2
        Console.WriteLine("{0} {1} {2}", item.OrderID, item.CustomerID, item.ProductID)
    Next
End Sub

Per eseguire questo metodo, incollarlo nella classe PLINQDataSample nel progetto PLINQ Data Sample e premere F5.

Vedi anche