共用方式為


HOW TO:處理 PLINQ 查詢中的例外狀況

更新:2010 年 5 月

本主題的第一個範例說明如何處理 PLINQ 查詢執行時可能擲回的 System.AggregateException。 第二個範例說明如何盡可能在即將擲回例外狀況之前,在委派內放置 try-catch 區塊。 透過這種方式,您可以在例外狀況發生時立即攔截例外狀況,並甚至繼續執行查詢。 如果可以將每個例外狀況個別擲回給聯結的執行緒,則引發例外狀況之後,查詢仍可能會繼續處理某些項目。

有時候,PLINQ 在回到循序執行方式後發生了例外狀況,這時可能會直接傳播例外狀況,而不是將例外狀況包在 AggregateException 中再傳播。 另外,系統一定會直接傳播 ThreadAbortException

注意事項注意事項

啟用 "Just My Code" 時,Visual Studio 會在擲回例外狀況的程式碼行處中斷,並顯示「使用者程式碼未處理的例外狀況」之類的錯誤訊息。這是良性的錯誤。您可以按 F5 從中斷的地方繼續,並看到下面範例所示的例外處理行為。若要防止 Visual Studio 在遇到第一個錯誤時就中斷,只要取消選取 [工具]、[選項]、[偵錯]、[一般] 下的 [Just My Code] 核取方塊即可。

這個範例是為了示範用法,執行速度可能比不上對應的循序 LINQ to Objects 查詢。如需加速的詳細資訊,請參閱認識 PLINQ 中的加速

範例

此範例說明如何在執行查詢的程式碼周圍放置 try-catch 區塊,以攔截擲回的 System.AggregateException

' Paste into PLINQDataSample class
Shared Sub PLINQExceptions_1()

    ' Using the raw string array here. See PLINQ Data Sample.
    Dim customers As String() = GetCustomersAsStrings().ToArray()

    ' First, we must simulate some currupt input.
    customers(20) = "###"

    'throws indexoutofrange
    Dim query = From cust In customers.AsParallel() _
        Let fields = cust.Split(","c) _
        Where fields(3).StartsWith("C") _
        Select fields
    Try
        ' We use ForAll although it doesn't really improve performance
        ' since all output is serialized through the Console.
        query.ForAll(Sub(e)
                         Console.WriteLine("City: {0}, Thread:{1}")
                     End Sub)
    Catch e As AggregateException

        ' In this design, we stop query processing when the exception occurs.
        For Each ex In e.InnerExceptions
            Console.WriteLine(ex.Message)
            If TypeOf ex Is IndexOutOfRangeException Then
                Console.WriteLine("The data source is corrupt. Query stopped.")
            End If
        Next
    End Try
End Sub
// Paste into PLINQDataSample class.
static void PLINQExceptions_1()
{
    // Using the raw string array here. See PLINQ Data Sample.
    string[] customers = GetCustomersAsStrings().ToArray();


    // First, we must simulate some currupt input.
    customers[54] = "###";

    var parallelQuery = from cust in customers.AsParallel()
                        let fields = cust.Split(',')
                        where fields[3].StartsWith("C") //throw indexoutofrange
                        select new { city = fields[3], thread = Thread.CurrentThread.ManagedThreadId };
    try
    {
        // We use ForAll although it doesn't really improve performance
        // since all output is serialized through the Console.
        parallelQuery.ForAll(e => Console.WriteLine("City: {0}, Thread:{1}", e.city, e.thread));
    }

    // In this design, we stop query processing when the exception occurs.
    catch (AggregateException e)
    {
        foreach (var ex in e.InnerExceptions)
        {
            Console.WriteLine(ex.Message);
            if (ex is IndexOutOfRangeException)
                Console.WriteLine("The data source is corrupt. Query stopped.");
        }
    }
}

在此範例中,查詢在例外狀況擲回後將無法繼續執行。 在您的應用程式程式碼攔截到例外狀況前,PLINQ 即已停止所有執行緒上的查詢。

下列範例說明如何在委派中放置 try-catch 區塊,以攔截例外狀況並繼續執行查詢。

' Paste into PLINQDataSample class
Shared Sub PLINQExceptions_2()

    Dim customers() = GetCustomersAsStrings().ToArray()
    ' Using the raw string array here.
    ' First, we must simulate some currupt input
    customers(20) = "###"

    ' Create a delegate with a lambda expression.
    ' Assume that in this app, we expect malformed data
    ' occasionally and by design we just report it and continue.
    Dim isTrue As Func(Of String(), String, Boolean) = Function(f, c)

                                                           Try

                                                               Dim s As String = f(3)
                                                               Return s.StartsWith(c)

                                                           Catch e As IndexOutOfRangeException

                                                               Console.WriteLine("Malformed cust: {0}", f)
                                                               Return False
                                                           End Try
                                                       End Function

    ' Using the raw string array here
    Dim query = From cust In customers.AsParallel()
                        Let fields = cust.Split(","c)
                        Where isTrue(fields, "C")
                       Select New With {.City = fields(3)}
    Try
        ' We use ForAll although it doesn't really improve performance
        ' since all output must be serialized through the Console.
        query.ForAll(Sub(e) Console.WriteLine(e.city))


        ' IndexOutOfRangeException will not bubble up      
        ' because we handle it where it is thrown.
    Catch e As AggregateException
        For Each ex In e.InnerExceptions
            Console.WriteLine(ex.Message)
        Next
    End Try
End Sub
// Paste into PLINQDataSample class.
static void PLINQExceptions_2()
{

    var customers = GetCustomersAsStrings().ToArray();
    // Using the raw string array here.
    // First, we must simulate some currupt input
    customers[54] = "###";

    // Create a delegate with a lambda expression.
    // Assume that in this app, we expect malformed data
    // occasionally and by design we just report it and continue.
    Func<string[], string, bool> isTrue = (f, c) =>
    {
        try
        {
            string s = f[3];
            return s.StartsWith(c);
        }
        catch (IndexOutOfRangeException e)
        {
            Console.WriteLine("Malformed cust: {0}", f);
            return false;
        }
    };

    // Using the raw string array here
    var parallelQuery = from cust in customers.AsParallel()
                        let fields = cust.Split(',')
                        where isTrue(fields, "C") //use a named delegate with a try-catch
                        select new { city = fields[3] };
    try
    {
        // We use ForAll although it doesn't really improve performance
        // since all output must be serialized through the Console.
        parallelQuery.ForAll(e => Console.WriteLine(e.city));
    }

    // IndexOutOfRangeException will not bubble up      
    // because we handle it where it is thrown.
    catch (AggregateException e)
    {
        foreach (var ex in e.InnerExceptions)
            Console.WriteLine(ex.Message);
    }
}

編譯程式碼

  • 若要編譯和執行這些範例,請將其複製到「PLINQ Data 範例」範例中,然後從 Main 呼叫方法。

穩固程式設計

如果您不知道如何處理例外狀況,請勿加以攔截,以免破壞程式的狀態。

請參閱

參考

ParallelEnumerable

概念

平行 LINQ (PLINQ)

變更記錄

日期

記錄

原因

2010 年 5 月

加入有關使用方式和 加速的比較注意事項。

客戶回函。