Compartilhar via


Como: Tratar exceções em uma consulta PLINQ

O primeiro exemplo neste tópico mostra como lidar com o System.AggregateException que pode ser lançada de uma consulta PLINQ quando ele executa. O segundo exemplo mostra como colocar a blocos try-catch dentro de delegados, tão perto quanto possível para onde a exceção será lançada. Dessa forma, você pode capturá-los tão logo eles ocorrem e possivelmente continuam a execução da consulta. Quando são permitidas exceções a emergir volta para o segmento de ingresso, em seguida, é possível que uma consulta pode continuar a processar alguns itens depois que a exceção é gerada.

Em alguns casos quando PLINQ volta para a execução seqüencial e ocorre uma exceção, a exceção pode ser propagada diretamente e não é disposta em um AggregateException. Além disso, ThreadAbortExceptions são sempre propagadas diretamente.

Observação

Quando "apenas meu código" é ativado, Visual Studio será quebrar na linha que lança a exceção e exibirá uma mensagem de erro que diz "exceção não tratada pelo código do usuário". Este erro é benigno.Pressione F5 para continuar a partir dele e ver o comportamento de manipulação de exceção é demonstrado nos exemplos abaixo.Para evitar que Visual Studio no primeiro erro, basta desmarcar o "Just My Code" caixa de seleção em Ferramentas, opções, depuração, geral.

Este exemplo destina-se para demonstrar o uso e pode não ser executado mais rápido do que o equivalente LINQ to Objects seqüencial de consulta de.Para obter mais informações sobre o aumento de velocidade, consulte Aumento de velocidade de compreensão no PLINQ.

Exemplo

Este exemplo mostra como colocar os blocos try-catch em torno do código que executa a consulta para capturar qualquer System.AggregateExceptions que são lançados.

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

Neste exemplo, a consulta não pode continuar depois que a exceção é lançada. No momento em que seu código de aplicativo captura a exceção, PLINQ já interrompeu a consulta em todos os threads.

O exemplo a seguir mostra como colocar um bloco try-catch um delegado para que seja possível capturar uma exceção e continuar com a execução da consulta.

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

Compilando o código

  • Para compilar e executar esses exemplos, copie o exemplo de amostra de dados do PLINQ e chamar o método de Main.

Programação robusta

Não captura uma exceção, a menos que você sabe como lidar com ele para que você não corromper o estado do seu programa.

Consulte também

Referência

ParallelEnumerable

Conceitos

Parallel LINQ PLINQ)

Histórico de alterações

Date

History

Motivo

Maio de 2010

Observação adicionada referentes ao uso vs. aumento de velocidade.

Comentários do cliente.