Печать строки "*" различной длины


Как новичок, я пробовал дрелью программирования. Метод возвращает перечислимый объект, который содержит числа, определяя, сколько "*" для печати на каждой линии.

public static void PrintStars(IEnumerable<int> neverEndingListOfInt)
{
    foreach (int item in neverEndingListOfInt)
    {
        Console.WriteLine(SetStars(item));
    }
}
private static string SetStars(int numberOfTimes)
{
    return string.Concat(Enumerable.Repeat("*", numberOfTimes));

}

У меня вот другая версия:

public static void PrintStars(IEnumerable<int> neverEndingListOfInt)
{

    foreach (int item in neverEndingListOfInt)
    {
        for (int i = 0; i < item; i++)
        {
            Console.Write("*");
        }
        Console.WriteLine();

    }
}

Какое влияние на GC будут создавать так много строк? Какой способ является более эффективным, и как бы вы предпочли это сделать?



166
2
задан 1 февраля 2018 в 07:02 Источник Поделиться
Комментарии
3 ответа

Я не считаю себя экспертом, когда дело доходит до внутренностей .Сборщик чистая фигня, но насколько я понимаю:


  • Write("*") выгоды от интернировании строк, поэтому не должно быть практически никаких затрат на сборку мусора (кроме того, что Write Не внутренне, конечно). Однако Write должен быть вызван для каждого символа, и этот звонок накладные делает его (значительно) медленнее.

  • В WriteLine вариант не выделить строки (между прочим), так что ГК будет работать чаще. Ли это имеет какое-либо существенное влияние на производительность-это то, что вы будете иметь, чтобы измерить, но это обычно не то, что вам нужно беспокоиться.

  • new string('*', numberOfTimes) является более эффективным (как с точки зрения скорости и с точки зрения распределения), чем string.Concat(Enumerable.Repeat("*", numberOfTimes)).

  • Вы можете столкнуться с разного рода проблемами, если вы выделяете много очень крупных объектов (более 85.000 байт), что обусловлено как большой объект кучи работ. Но это, наверное, не уместны в данном случае.

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

3
ответ дан 1 февраля 2018 в 09:02 Источник Поделиться

Использовать один буфер

Кажется (на моем компьютере, по крайней мере), что накладные расходы на создание много строк, как менее важна, чем накладные расходы на повторные вызовы Console.Write(). Однако, мы вполне можем получить лучшее из обоих миров с помощью буфера звезд, и с помощью Console.WriteLine(char[] buffer, int index, int count) перегрузки: создать одну большую строку (буфер) и просто читать столько, сколько нам нужно каждый раз.

Код

public static void PrintStars5(IEnumerable<int> neverEndingListOfInt)
{
char[] buffer = new char[1];

foreach (int item in neverEndingListOfInt)
{
if (item > buffer.Length)
{ // increase size of buffer
int c = buffer.Length;
while (c < item)
{
c *= 2; // double size
}
buffer = new string('*', c).ToCharArray();
}

Console.WriteLine(buffer, 0, item);
}
}

Преимущества


  • Только один звонок WriteLine() за штуку

  • Количество выделений (в коде) по логарифмической зависимости по отношению к величине элемент (не зависит от количества элементов)

  • Использует не более чем четыре столько же памяти, как ваше решение.

Доказательств

Вот график, показывающий, какое-то время-измерение 2-х различных методов на различных наборов равномерно распределенных чисел (предупреждение: разделали сюжет журнала/журнала):

enter image description here

На оси абсцисс-тип IEnumerable<int>: Acc<n> значит, прикинь n, Dec<n> означает отсчет от n, Rnd<n> средства производства n случайных чисел в диапазоне [0,n].

Это показывает, что, кажется, этот буферизованный метод опережая ваше первое решение (с string.ctor(char, int) исправить, как полагают другие) дольше/больше строк.

Интересно посмотреть, насколько хорошо string.ctor(char, int) выполняет. Это externed функция, которая помогает, Но как строки сделать больше, я бы ожидать буферизации, чтобы погасить все больше и больше.

Граф не должен быть полностью довольным (если бы я мог быть обеспокоен, чтобы оставить ее работать в течение времени, мы можем увидеть буферизованный способ действительно приносит плоды более крупные и более чисел. Вы должны абсолютно игнорировать результаты для малых n. Каждая точка данных является общее время, необходимое для 100 повторов (тасуются каждые 10). Мне извиниться за то, как ужасно стайлинг сюжет, я не знаю, как использовать электронную таблицу программного обеспечения.

Предостережения

Хотя я не сомневаюсь в том, что буферизация в путь за этой игрушкой проблемы, следует отметить, что хотя Console.Write методы были на 2 порядка медленнее (на моей машине), чем тягучий методы (они не наносятся, потому что я отдал их ждет), это не распространяется на другие потоки. Примечание: Я проверил код в релиз, трубопроводов и stdout в nul, который я бы подумал, что бы минимизировать нагрузку в Console.Writeно я действительно не знаю

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

2
ответ дан 2 февраля 2018 в 05:02 Источник Поделиться

Строк .Сеть "интернировать" означает, что каждая строка, которую вы создаете кэшируется для жизни приложения, поэтому если вы используете два раза одну и ту же строку, вы используете один и тот же экземпляр, как и раньше. Что касается сбора мусора, то я не думаю, что это важно. Используя цикл for, вероятно, быстрее, чем хотя бы перечисли.

Вижу этот вопрос: https://stackoverflow.com/questions/8054471/string-interning-in-net-framework-what-are-the-benefits-and-when-to-use-inter

1
ответ дан 1 февраля 2018 в 09:02 Источник Поделиться