Sdílet prostřednictvím


Postupy: Zpracování výjimek v PLINQ dotazu

První příklad v tomto tématu ukazuje, jak zpracovat výjimku System.AggregateException, která může být vyvolána z PLINQ dotazu, jakmile je spuštěn. Druhý příklad ukazuje, jak umístit bloky try-catch v rámci delegátů, co nejblíže k místu, kde bude vyvolána výjimka. Tímto způsobem je možno zachytit výjimky ihned jakmile k nim dojde a případně pokračovat v provádění dotazu. Pokud je výjimkám umožněno probublat zpět do spojovacího vlákna, je možné aby úloha pokračovala ve zpracování některých položek i po tom co nastala výjimka.

V některých případech, když PLINQ přejde zpět k sekvenčnímu provádění a dojde k výjimce, výjimka může být šířena přímo, nikoliv obalena do AggregateException. Navíc výjimky ThreadAbortException jsou vždy šířeny přímo.

PoznámkaPoznámka

Pokud je povolená vlastnost "Pouze můj kód", Visual Studio zastaví na řádce, která vyvolala výjimku, a zobrazí chybovou zprávu s upozorněním, že výjimka není zpracována uživatelským kódem. Tato chyba je neškodná.Stiskem klávesy F5 lze pokračovat a zjistit jak jsou výjimky zpracovány. Toto je znázorněno v příkladech níže.Chcete-li zabránit Visual Studiu v zastavení na první chybě, zrušte zaškrtávací políčko "Pouze můj kód" v menu Nástroje, Možnosti ladění, Obecné.

Tento příklad je určen k prokázání využití a může běžet rychleji než ekvivalentní sekvenční LINQ dotazu objektů.Další informace o Vančurovou Principy Vančurovou v PLINQ.

Příklad

Tento příklad ukazuje, jak umístit bloky try-catch okolo kódu, který spouští dotaz, k zachycení všech vyvolaných výjimek 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.");
        }
    }
}

V tomto příkladu nemůže dotaz pokračovat poté, co je vyvolána výjimka. V době, kdy kód aplikace zachytí výjimku, PLINQ již zastavil dotaz ve všech vláknech.

Následující příklad ukazuje, jak vložit do kódu delegáta blok try-catch, aby bylo možné zachytit výjimku a pokračovat v provádění dotazu.

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

Probíhá kompilace kódu

  • Pro zkompilování a spuštění těchto příkladů je možno je zkopírovat do příkladu PLINQ Data Sample a zavolat metodu z Main.

Robustní programování

Nezachytávejte výjimku, pokud nevíte, jak ji zpracovat, aby nedošlo k poškození stavu programu.

Viz také

Odkaz

ParallelEnumerable

Koncepty

Paralelní LINQ (PLINQ)

Historie změn

Datum

Poslední dokumenty

Důvod

Květen 2010

Byla přidána poznámka týkající se používání vs. Vančurovou.

Názory zákazníků