Pergunta

out parâmetros tem quaisquer implicações C # desempenho que eu deveria saber? (Exceções como)

Quer dizer, é uma boa idéia ter um método com um parâmetro out em um loop que irá executar um par de milhões de vezes por segundo?

Eu sei que é feio, mas eu estou usando-o da mesma forma que Int32.TryParse é usá-los -. Retornando um bool de dizer se alguma validação foi bem sucedida e ter um parâmetro out contendo alguns dados adicionais, se ele foi bem sucedido

Foi útil?

Solução

Eu duvido que você vai encontrar qualquer penalidade de desempenho significativo para usando um parâmetro out. Você tem que obter informações de volta para o chamador de alguma forma ou de outra - out é apenas uma maneira diferente de fazê-lo. Você pode encontrar lá é alguns penalidade se você usar o parâmetro extensivamente dentro do método, pois pode muito bem significar um nível extra de redirecionamento para cada acesso. No entanto, eu não esperaria que ele seja significativo. Como normal, escrever o código mais legível e teste se o desempenho já é bom o suficiente antes de tentar otimizar ainda mais.

EDIT: O resto este é um aparte, de forma eficaz. É apenas realmente relevante para grandes tipos de valor, que deve ser evitada qualquer maneira:)

Não concordo com a afirmação de Konrad sobre os "valores de retorno para todos os tipos> 32 bit são tratados semelhantes ou idênticos aos de fora argumentos sobre o nível da máquina de qualquer maneira" embora. Aqui está um pequeno aplicativo de teste:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

struct BigStruct
{
    public Guid guid1, guid2, guid3, guid4;
    public decimal dec1, dec2, dec3, dec4;
}

class Test
{
    const int Iterations = 100000000;

    static void Main()
    {
        decimal total = 0m;
        // JIT first
        ReturnValue();
        BigStruct tmp;
        OutParameter(out tmp);

        Stopwatch sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            BigStruct bs = ReturnValue();
            total += bs.dec1;
        }
        sw.Stop();
        Console.WriteLine("Using return value: {0}",
                          sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            BigStruct bs;
            OutParameter(out bs);
            total += bs.dec1;
        }
        Console.WriteLine("Using out parameter: {0}",
                          sw.ElapsedMilliseconds);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static BigStruct ReturnValue()
    {
        return new BigStruct();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static void OutParameter(out BigStruct x)
    {
        x = new BigStruct();
    }
}

Resultado:

Using return value: 11316
Using out parameter: 7461

Basicamente, usando um out parâmetro estamos escrevendo os dados diretamente para o destino final, em vez de escrevê-lo para quadro de pilha pequena do método e, em seguida, copiá-lo de volta ao quadro de pilha do método principal.

Sinta-se livre para criticar o aplicativo de benchmark embora - Talvez eu tenha perdido alguma coisa

Outras dicas

Não é um problema de desempenho, mas algo que veio antes - você não pode usá-los com variância em C # 4.0 .

Pessoalmente, eu tendem a usar parâmetros out uma quantidade razoável na minha privada código (ou seja, dentro de uma classe, tendo um método que retorna vários valores sem o uso de um tipo separado) - mas eu tendem a evitar -los na API público, exceto para o padrão bool Try{Something}(out result).

Não há implicações de desempenho. out é basicamente o mesmo que qualquer velha passagem de argumento, de um ponto de vista técnico. Embora possa parecer plausível que enormes amounds de dados são copiados (por exemplo, para grandes estruturas), este é realmente o mesmo que para valores de retorno.

Na verdade, valores de retorno para todos os tipos> 32 bit são tratados semelhantes aos argumentos out na> nível da máquina de qualquer maneira.

Por favor note que a última declaração não sugere que retornar um parâmetro out valor == em .NET. benchmark mostra de Jon que este é, obviamente, (e infelizmente) não é o caso. Na verdade, para torná-lo idêntico, chamado valor de retorno otimização é empregue em compiladores C ++. Algo semelhante poderia ser feito em versões futuras do JIT para melhorar o desempenho de retorno de grandes estruturas (no entanto, uma vez que grandes estruturas são bastante raro em .NET, isso pode ser uma otimização desnecessário).

No entanto , (e com o meu conhecimento muito limitado de x86 assembly), retornando objetos de chamadas de função geralmente implica alocação de espaço suficiente no site da chamada, empurrando o endereço na pilha e preenchê-lo, copiando o valor de retorno para ele. Este é basicamente o mesmo que out faz apenas omitindo uma cópia temporária desnecessária do valor desde o local de memória alvo pode ser acessado diretamente.

A principal razão para evitar os parâmetros é a legibilidade do código, em vez de desempenho.

Para tipos de valores não há nenhuma diferença real de qualquer maneira (eles sempre copiar) e para tipos de referência é basicamente o mesmo que passar por ref.

vezes Nove em cada dez é melhor você criar a sua própria classe de registro mudo, ao invés de usar um parâmetro de saída -. Isso é mais fácil de ler e entender quando você retornar para o código mais tarde

parâmetros

Fora são passados ??por ref. Assim, apenas um ponteiro passado na pilha.

Se o seu tipo de valor é grande, há menos cópia, mas então você tem que cancelar o ponteiro sobre cada uso variável.

Usando um parâmetro de saída faz desempenho não doer. parâmetro um fora é basicamente um parâmetro de referência, de modo que o chamador eo ponto receptor para o mesmo pedaço de memória.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top