Использует StringBuilder, Удаляют метод больше памяти, эффективной, чем создание нового StringBuilder в цикле?

Этот ответ может быть тривиальным / очевидным, но вы можете просто пойти дальше и выполнить слияние:

# from your target branch
git merge feature

Если вы столкнулись с некоторыми неприятными конфликтами слияния и хотите выручить, просто используйте: [114 ]

git merge --abort

Если объединение действительно завершается без конфликтов, но вы не хотите его сохранять, вы можете сбросить его:

git reset --hard HEAD~1

Примечание. Этот ответ предполагает, что вы делать все это локально, а не на удаленном сервере Git. Если вы используете что-то вроде Bitbucket или GitHub, то уже должна быть функция, которая делает примерно то, что вы хотите. Вы можете создать запрос на извлечение, и в случае непроходимых конфликтов слияния пользовательский интерфейс предупредит вас об этом.

8
задан Sixto Saez 5 November 2008 в 22:11
поделиться

10 ответов

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

Я изменил опцию № 1 использовать в своих интересах @Ty предложение для использования StringBuilder. Длина = 0 вместо Удалить метода. Это сделало код этих двух опций более подобным. Эти два различия теперь, является ли конструктор для StringBuilder в или из цикла, и опция № 1 теперь использует метод Длины для очистки StringBuilder. Обе опции были установлены работать на основе массива outputStrings с 100 000 элементов, чтобы заставить сборщик "мусора" сделать некоторую работу.

Пара ответов предложила подсказки, чтобы посмотреть на различные счетчики PerfMon и такой и использовать результаты для выбора опции. Я провел некоторое исследование и закончил тем, что использовал встроенный Проводник Производительности Системного выпуска Разработчика Команды Visual Studio, который я имею на работе. Я нашел вторую запись в блоге многослойного ряда, который объяснил, как настроить ее здесь. В основном Вы обеспечиваете электричеством модульный тест для указания на код, который Вы хотите представить; пройдите мастер и некоторые конфигурации; и запустите профилирование модульного теста. Я включил выделение объекта.NET и пожизненные метрики. Результаты профилирования, где трудный для форматирования для этого ответа, таким образом, я разместил их в конце. Если Вы будете копировать и вставлять текст в Excel и массажировать их немного, то они будут читаемы.

Опция № 1 является большей частью эффективности памяти, потому что она делает сборщик "мусора", действительно немного меньше работают, и она выделяет половину памяти и экземпляров к объекту StringBuilder, чем Опция № 2. Для повседневного кодирования, выбирая опцию № 2 прекрасно подходит.

Если Вы все еще читаете, я задал этот вопрос, потому что Опция № 2 сделает детекторы утечки памяти опыта, разработчик C/C++ идет баллистический. Огромная утечка памяти произойдет, если экземпляр StringBuilder не будет выпущен прежде чем быть повторно присвоенным. Конечно, мы, которых разработчики C# не волнуют по поводу таких вещей (пока они не подпрыгивают и кусают нас). Благодаря всем!!


ClassName   Instances   TotalBytesAllocated Gen0_InstancesCollected Gen0BytesCollected  Gen1InstancesCollected  Gen1BytesCollected
=======Option #1                    
System.Text.StringBuilder   100,001 2,000,020   100,016 2,000,320   2   40
System.String   301,020 32,587,168  201,147 11,165,268  3   246
System.Char[]   200,000 8,977,780   200,022 8,979,678   2   90
System.String[] 1   400,016 26  1,512   0   0
System.Int32    100,000 1,200,000   100,061 1,200,732   2   24
System.Object[] 100,000 2,000,000   100,070 2,004,092   2   40
======Option #2                 
System.Text.StringBuilder   200,000 4,000,000   200,011 4,000,220   4   80
System.String   401,018 37,587,036  301,127 16,164,318  3   214
System.Char[]   200,000 9,377,780   200,024 9,379,768   0   0
System.String[] 1   400,016 20  1,208   0   0
System.Int32    100,000 1,200,000   100,051 1,200,612   1   12
System.Object[] 100,000 2,000,000   100,058 2,003,004   1   20
7
ответ дан 5 December 2019 в 07:37
поделиться

В то время как Ваше профилирование, Вы могли также попытаться просто обнулить длину StringBuilder при вводе цикла.

formattedOutput.Length = 0;
4
ответ дан 5 December 2019 в 07:37
поделиться

Опция 2 должна (я верить), на самом деле превосходят опцию 1 по характеристикам. Действие вызова Remove "вынуждает" StringBuilder сделать копию строки, это уже возвращается. Строка на самом деле изменяема в StringBuilder, и StringBuilder не делает копию, если это не должно. С опцией 1 это копирует, прежде в основном убрать массив - с опцией 2 никакая копия не требуется.

Единственный недостаток опции 2 - то, что, если строка заканчивает тем, что была длинна, будет несколько копий, сделанных при добавлении - тогда как опция 1 сохраняет первоначальный размер буфера. Если это будет случаем, однако, укажите начальную возможность избежать дополнительного копирования. (В Вашем примере кода строка закончит тем, что была больше, чем значение по умолчанию 16 символов - инициализация, это со способностью, скажем, 32 уменьшит дополнительные требуемые строки.)

Кроме производительности, однако, опция 2 является просто инструментом для очистки.

6
ответ дан 5 December 2019 в 07:37
поделиться

Так как Вы заинтересованы только с памятью, я предложил бы:

foreach (string outputString in outputStrings)
    {    
        string output = "prefix " + outputString + " postfix";
        ExistingOutputMethodThatOnlyTakesAString(output)  
    }

Названный вывод переменной является тем же размером в Вашей исходной реализации, но никакие другие объекты не необходимы. StringBuilder использует строки и другие объекты внутренне, и Вы будете созданы много объектов, которые должны быть GC'd.

Оба строка от опции 1:

string output = formattedOutput.ToString();

И строка от опции 2:

ExistingOutputMethodThatOnlyTakesAString(
           formattedOutputInsideALoop.ToString());

создаст неизменный объект со значением префикса + outputString + постфикс. Эта строка является тем же размером, неважно, как Вы создаете его. То, что Вы действительно спрашиваете, - который является большей эффективной памятью:

    StringBuilder formattedOutput = new StringBuilder(); 
    // create new string builder

или

    formattedOutput.Remove(0, output.Length); 
    // reuse existing string builder

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

Если действительно необходимо знать, какой из этих двух более эффективен в приложении (это будет, вероятно, варьироваться на основе размера списка, префикса и outputStrings), я рекомендовал бы Профилировщику МУРАВЬЕВ красного логического элемента http://www.red-gate.com/products/ants_profiler/index.htm

Jason

2
ответ дан 5 December 2019 в 07:37
поделиться

Ненависть для высказывания этого, но как насчет того, чтобы просто тестировать его?

1
ответ дан 5 December 2019 в 07:37
поделиться

Этот материал легко узнать собой. Выполните Perfmon.exe и добавьте счетчик для Памяти.NET + Генерал 0 Наборов. Выполните тестовый код миллион раз. Вы будете видеть, что опция № 1 требует половины количества потребностей наборов опций № 2.

1
ответ дан 5 December 2019 в 07:37
поделиться

Мы говорили об этом прежде с Java, вот [Выпуск] результаты версии C#:

Option #1 (10000000 iterations): 11264ms
Option #2 (10000000 iterations): 12779ms

Обновление: В моем ненаучном анализе, позволяющем эти два метода выполниться при контроле всех счетчиков производительности памяти в perfmon, не привел ни к какому виду заметного различия ни с одним методом (кроме наличия некоторого скачка счетчиков только, в то время как любой тест выполнялся).

И вот то, что я раньше тестировал:

class Program
{
    const int __iterations = 10000000;

    static void Main(string[] args)
    {
        TestStringBuilder();
        Console.ReadLine();
    }

    public static void TestStringBuilder()
    {
        //potentially a collection with several hundred items:
        var outputStrings = new [] { "test1", "test2", "test3" };

        var stopWatch = new Stopwatch();

        //Option #1
        stopWatch.Start();
        var formattedOutput = new StringBuilder();

        for (var i = 0; i < __iterations; i++)
        {
            foreach (var outputString in outputStrings)
            {
                formattedOutput.Append("prefix ");
                formattedOutput.Append(outputString);
                formattedOutput.Append(" postfix");

                var output = formattedOutput.ToString();
                ExistingOutputMethodThatOnlyTakesAString(output);

                //Clear existing string to make ready for next iteration:
                formattedOutput.Remove(0, output.Length);
            }
        }
        stopWatch.Stop();

        Console.WriteLine("Option #1 ({1} iterations): {0}ms", stopWatch.ElapsedMilliseconds, __iterations);
            Console.ReadLine();
        stopWatch.Reset();

        //Option #2
        stopWatch.Start();
        for (var i = 0; i < __iterations; i++)
        {
            foreach (var outputString in outputStrings)
            {
                StringBuilder formattedOutputInsideALoop = new StringBuilder();

                formattedOutputInsideALoop.Append("prefix ");
                formattedOutputInsideALoop.Append(outputString);
                formattedOutputInsideALoop.Append(" postfix");

                ExistingOutputMethodThatOnlyTakesAString(
                   formattedOutputInsideALoop.ToString());
            }
        }
        stopWatch.Stop();

        Console.WriteLine("Option #2 ({1} iterations): {0}ms", stopWatch.ElapsedMilliseconds, __iterations);
    }

    private static void ExistingOutputMethodThatOnlyTakesAString(string s)
    {
        // do nothing
    }
} 

Опция 1 в этом сценарии незначительно быстрее, хотя опцию 2 легче считать и поддержать. Если Вы, оказывается, не выполняете эту операцию миллионы времен вплотную, я придерживался бы Опции 2, потому что я подозреваю, что опция 1 и 2 о том же при выполнении в единственном повторении.

1
ответ дан 5 December 2019 в 07:37
поделиться

Я сказал бы что опция № 2 если определенно более простой. С точки зрения производительности, походит на что-то, что необходимо было бы просто протестировать и видеть. Я предположил бы, что это не имеет достаточного значения для выбора менее простой опции.

0
ответ дан 5 December 2019 в 07:37
поделиться

Я думаю, что опция 1 была бы немного большей памятью, эффективной, поскольку новый объект не создается каждый раз. Однако GC делает довольно хорошее задание чистки ресурсов как в опции 2.

Я думаю, что можно попадать в прерывание преждевременной оптимизации (корень всего зла - Knuth). Ваш IO собирается взять намного больше ресурсов, чем строковый разработчик.

Я склоняюсь, идут с более ясной/более чистой опцией, в этой опции 2 случая.

Ограбить

0
ответ дан 5 December 2019 в 07:37
поделиться
  1. Измерьте его
  2. Предварительно выделите максимально близко тому, сколько памяти Вы думаете, что Вам будет нужно
  3. Если скорость является Вашим предпочтением, то рассмотрите довольно прямую многопоточную переднюю сторону к середине, середина для окончания параллельного подхода (разверните разделение труда как требуется),
  4. измерьте его снова

что более важно для Вас?

  1. память

  2. скорость

  3. ясность

0
ответ дан 5 December 2019 в 07:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: