Gewusst wie: Behandeln von Ausnahmen in einer PLINQ-Abfrage

Im ersten Beispiel in diesem Thema wird gezeigt, wie die System.AggregateException behandelt wird, die beim Ausführen einer PLINQ-Abfrage ausgelöst werden kann. Im zweiten Beispiel wird gezeigt, wie try/catch-Blöcke in Delegate möglichst nah an der Position eingefügt werden, an der die Ausnahme ausgelöst wird. Auf diese Weise können Sie die Ausnahmen sofort erfassen und die Abfrageausführung möglicherweise fortsetzen. Wenn Ausnahmen mittels Bubbling wieder an den Verbindungsthread übergeben werden können, ist es möglich, dass eine Abfrage nach dem Auslösen der Ausnahme weiterhin einige Elemente verarbeitet.

Wenn PLINQ auf die sequenzielle Ausführung zurückgreift und eine Ausnahme auftritt, kann die Ausnahme in einigen Fällen direkt weitergegeben werden, ohne sie in eine AggregateException einzuschließen. Zudem werden ThreadAbortExceptions immer direkt weitergegeben.

HinweisHinweis

Wenn "Nur eigenen Code" aktiviert ist, unterbricht Visual Studio die Ausführung in der Zeile, die die Ausnahme auslöst, und eine Fehlermeldung zu einer nicht vom Benutzercode behandelten Ausnahme wird angezeigt. Dieser Fehler hat keine Auswirkungen.Sie können F5 drücken, um den Vorgang fortzusetzen. In diesem Fall wird das in den unten stehenden Beispielen veranschaulichte Ausnahmebehandlungsverhalten angewendet.Um zu verhindern, dass Visual Studio die Ausführung beim ersten Fehler unterbricht, deaktivieren Sie das Kontrollkästchen "Nur eigenen Code" unter Extras, Optionen, Debugging, Allgemein.

Dieses Beispiel soll die Verwendung veranschaulichen, und es wird möglicherweise nicht schneller als die entsprechende sequenzielle LINQ to Objects-Abfrage ausgeführt.Weitere Informationen über Geschwindigkeitssteigerungen finden Sie unter Grundlagen zur Beschleunigung in PLINQ.

Beispiel

In diesem Beispiel wird gezeigt, wie Sie die try/catch-Blöcke um den Code platzieren, der die Abfrage ausführt, sodass alle ausgelösten System.AggregateException-Ausnahmen erfasst werden.

' 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.");
        }
    }
}

In diesem Beispiel kann die Abfrage nicht fortgesetzt werden, nachdem die Ausnahme ausgelöst wurde. Wenn der Anwendungscode die Ausnahme erfasst, hat PLINQ die Abfrage bereits in allen Threads beendet.

Im folgenden Beispiel wird gezeigt, wie Sie einen try/catch-Block in einen Delegaten einfügen, um eine Ausnahme erfassen und die Abfrageausführung fortsetzen zu können.

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

Kompilieren des Codes

  • Um diese Beispiele zu kompilieren und auszuführen, kopieren Sie sie in das PLINQ-Datenbeispiel, und rufen Sie die Methode vom Hauptmenü aus auf.

Robuste Programmierung

Erfassen Sie Ausnahmen nur, wenn Sie wissen, wie diese behandelt werden, damit der Zustand des Programms nicht beschädigt wird.

Siehe auch

Referenz

ParallelEnumerable

Konzepte

Paralleles LINQ (PLINQ)

Änderungsprotokoll

Datum

Versionsgeschichte

Grund

Mai 2010

Hinweis bezüglich Verwendung und Geschwindigkeitssteigerung hinzugefügt.

Kundenfeedback.