如何:在 PLINQ 查询中控制排序

这些示例演示如何使用 AsOrdered 扩展方法在 PLINQ 查询中控制排序。

警告说明警告

这些示例主要旨在演示用法,运行速度可能比也可能不如等效的顺序 LINQ to Objects 查询快。

示例

下面的示例保留源序列的排序。 有时这是必要的;例如,某些查询运算符需要经过排序的源序列才能生成正确的结果。

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
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 v in parallelQuery)
    Console.Write("{0} ", v);

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

下面的示例演示一些可能需要对其源序列进行排序的查询运算符。 这些运算符将适用于未排序的序列,但可能会产生意外的结果。

' 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
// 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);

}

若要运行此方法,请将其粘贴到 PLINQ 数据示例项目的 PLINQDataSample 类中,然后按 F5。

下面的示例演示如何保留查询第一部分的排序,然后移除排序以提高 join 子句的性能,接着将排序重新应用于最终结果序列。

' 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
// 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);

}

若要运行此方法,请将其粘贴到 PLINQ 数据示例项目的 PLINQDataSample 类中,然后按 F5。

请参见

参考

ParallelEnumerable

概念

并行 LINQ (PLINQ)