Вопрос

Делай вон параметры в C# есть какие-либо последствия для производительности, о которых я должен знать?(Например, исключения)

Я имею в виду, хорошая ли это идея - иметь метод с out параметр в цикле, который будет выполняться пару миллионов раз в секунду?

Я знаю, что это некрасиво, но я использую его так же, как Int32.TryParse использует их - возвращает bool чтобы сообщить, прошла ли какая-то проверка успешно, и наличие out параметр, содержащий некоторые дополнительные данные, если это было успешно.

Это было полезно?

Решение

Я сомневаюсь, что вы обнаружите какое-либо существенное снижение производительности при использовании out параметр.Вы должны так или иначе вернуть информацию звонящему - out это просто другой способ сделать это.Вы можете обнаружить, что есть некоторые штраф, если вы широко используете параметр out в рамках метода, поскольку это вполне может означать дополнительный уровень перенаправления для каждого доступа.Однако я бы не ожидал, что это будет что-то значительное.Как обычно, напишите наиболее читаемый код и проверьте, достаточно ли высока производительность прежде чем пытаться оптимизировать дальше.

Редактировать:Все остальное, по сути, является отступлением в сторону.Это действительно актуально только для больших типов значений, чего обычно следует избегать в любом случае :)

Однако я не согласен с утверждением Конрада о том, что "возвращаемые значения для всех типов > 32 бит в любом случае обрабатываются аналогично или идентично аргументам out на машинном уровне".Вот небольшое тестовое приложение:

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

Результаты:

Using return value: 11316
Using out parameter: 7461

По сути, используя параметр out, мы записываем данные непосредственно в конечный пункт назначения, вместо того чтобы записывать их во фрейм стека малого метода, а затем копировать обратно во фрейм стека основного метода.

Однако не стесняйтесь критиковать приложение benchmark - возможно, я что-то пропустил!

Другие советы

Не проблема с производительностью, а то, что возникло ранее - вы не можете использовать их с различиями в C # 4.0.

Лично я склонен использовать out параметров изрядное количество в моем Частное код (т.е.внутри класса, имеющего метод, который возвращает несколько значений без использования отдельного типа) - но я склонен избегать их в общедоступном API, за исключением bool Try{Something}(out result) шаблон.

Это не влияет на производительность. out с технической точки зрения, это в основном то же самое, что и любая передача старого аргумента.Хотя может показаться правдоподобным, что копируются огромные массивы данных (напримердля больших структур), это фактически то же самое, что и для возвращаемых значений.

Фактически, возвращаемые значения для всех типов > 32 бит обрабатываются аналогично out аргументы по поводу машинный уровень в любом случае.

Пожалуйста, обратите внимание, что последнее утверждение не предполагает, что возвращаемое значение == out параметр в файле .NET.Тест Джона показывает, что это явно (и, к сожалению) не так.На самом деле, чтобы сделать его идентичным, оптимизация именованного возвращаемого значения используется в компиляторах C ++.Нечто подобное потенциально можно было бы сделать в будущих версиях JIT для повышения производительности возврата больших структур (однако, поскольку большие структуры довольно редки в .NET, это может оказаться ненужной оптимизацией).

Однако, (и с моими очень ограниченными знаниями сборки x86), возврат объектов из вызовов функций обычно влечет за собой выделение достаточного пространства на сайте вызова, добавление адреса в стек и заполнение его путем копирования в него возвращаемого значения.Это в основном то же самое , что out выполняет, только опуская ненужную временную копию значения, поскольку к целевой ячейке памяти можно получить прямой доступ.

Основной причиной отказа от использования out parameters является удобочитаемость кода, а не производительность.

Для типов значений в любом случае нет реальной разницы (они всегда копируются), а для ссылочных типов это в основном то же самое, что передача по ссылке.

В девяти случаях из десяти вам лучше создать свой собственный класс dumb record, а не использовать параметр out - это проще прочитать и понять, когда вы вернетесь к коду позже.

Параметры Out передаются по ссылке.Таким образом, в стек передается только указатель.

Если ваш тип значения большой, объем копирования будет меньше, но тогда вам придется разыменовывать указатель на каждую используемую переменную.

Использование параметра out не снижает производительность.Параметр Out в основном является ссылочным параметром, поэтому и вызывающий объект, и вызываемый получатель указывают на один и тот же фрагмент памяти.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top