Строка произвела: формат или concat в C#?

Используя реализацию Task.WhenAny, вы можете создать как перегрузку расширения, которая также получает фильтр.

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

Что-то вроде этого:

static class TasksExtensions
{
    public static Task<Task<T>> WhenAny<T>(this IList<Task<T>> tasks, Func<T, bool> filter)
    {
        CompleteOnInvokePromiseFilter<T> action = new CompleteOnInvokePromiseFilter<T>(filter);

        bool flag = false;
        for (int i = 0; i < tasks.Count; i++)
        {
            Task<T> completingTask = tasks[i];

            if (!flag)
            {
                if (action.IsCompleted) flag = true;
                else if (completingTask.IsCompleted)
                {
                    action.Invoke(completingTask);
                    flag = true;
                }
                else completingTask.ContinueWith(t =>
                {
                    action.Invoke(t);
                });
            }
        }

        return action.Task;
    }
}

class CompleteOnInvokePromiseFilter<T>
{
    private int firstTaskAlreadyCompleted;
    private TaskCompletionSource<Task<T>> source;
    private Func<T, bool> filter;

    public CompleteOnInvokePromiseFilter(Func<T, bool> filter)
    {
        this.filter = filter;
        source = new TaskCompletionSource<Task<T>>();
    }

    public void Invoke(Task<T> completingTask)
    {
        if (completingTask.Status == TaskStatus.RanToCompletion && 
            filter(completingTask.Result) && 
            Interlocked.CompareExchange(ref firstTaskAlreadyCompleted, 1, 0) == 0)
        {
            source.TrySetResult(completingTask);
        }
    }

    public Task<Task<T>> Task { get { return source.Task; } }

    public bool IsCompleted { get { return source.Task.IsCompleted; } }
}

Вы можете использовать этот метод расширения следующим образом:

List<Task<int>> tasks = new List<Task<int>>();    
...Initialize Tasks...

var task = await tasks.WhenAny(x => x % 2 == 0);

//In your case would be something like tasks.WhenAny(b => b);
175
задан 6 revs, 4 users 63% 28 October 2013 в 17:41
поделиться

27 ответов

Попробуйте этот код.

Это - немного измененная версия Вашего кода.
1. Я удалил Консоль. WriteLine, поскольку это - вероятно, немного порядков величины медленнее, чем, что я пытаюсь измерить.
2. Я запускаю Секундомер перед циклом и останавливаю его прямо после, этот способ, которым я не теряю точность, если функция берет, например, 26,4 галочек для выполнения.
3. Путем Вы разделились, результат некоторыми повторениями был неправильным. Посмотрите то, что происходит, если у Вас есть 1 000 миллисекунд и 100 миллисекунд. В обеих ситуациях Вы получите 0 мс после деления его 1000000.

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (p.FirstName + " " + p.LastName);
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();
s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", p.FirstName, p.LastName);
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();


Console.Clear();
Console.WriteLine(n.ToString()+" x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Thread.Sleep(4000);

Те - мои результаты:

1000000 x заканчиваются = строка. Формат (" {0} {1} ", p. FirstName, p. LastName); взял: галочки на 618 мс - 2213706
1000000 x заканчиваются = (p. FirstName +" "+ p. LastName); взял: галочки на 166 мс - 595610

88
ответ дан 8 revs, 6 users 55% 23 November 2019 в 20:25
поделиться

Мне было любопытно где StringBuilder, выдержанный с этими тестами. Результаты ниже...

class Program {
   static void Main(string[] args) {

      var p = new { FirstName = "Bill", LastName = "Gates" };

      var tests = new[] {
         new { Name = "Concat", Action = new Action(delegate() { string x = p.FirstName + " " + p.LastName; }) },
         new { Name = "Format", Action = new Action(delegate() { string x = string.Format("{0} {1}", p.FirstName, p.LastName); }) },
         new { Name = "StringBuilder", Action = new Action(delegate() {
            StringBuilder sb = new StringBuilder();
            sb.Append(p.FirstName);
            sb.Append(" ");
            sb.Append(p.LastName);
            string x = sb.ToString();
         }) }
      };

      var Watch = new Stopwatch();
      foreach (var t in tests) {
         for (int i = 0; i < 5; i++) {
            Watch.Reset();
            long Elapsed = ElapsedTicks(t.Action, Watch, 10000);
            Console.WriteLine(string.Format("{0}: {1} ticks", t.Name, Elapsed.ToString()));
         }
      }
   }

   public static long ElapsedTicks(Action ActionDelg, Stopwatch Watch, int Iterations) {
      Watch.Start();
      for (int i = 0; i < Iterations; i++) {
         ActionDelg();
      }
      Watch.Stop();
      return Watch.ElapsedTicks / Iterations;
   }
}

Результаты:

Concat: 406 ticks
Concat: 356 ticks
Concat: 411 ticks
Concat: 299 ticks
Concat: 266 ticks
Format: 5269 ticks
Format: 954 ticks
Format: 1004 ticks
Format: 984 ticks
Format: 974 ticks
StringBuilder: 629 ticks
StringBuilder: 484 ticks
StringBuilder: 482 ticks
StringBuilder: 508 ticks
StringBuilder: 504 ticks
1
ответ дан 2 revs 23 November 2019 в 20:25
поделиться

Первый (формат) выглядит лучше мне. Это более читаемо, и Вы не создаете дополнительные временные строковые объекты.

1
ответ дан Rismo 23 November 2019 в 20:25
поделиться

О, и только для полноты, следующее является несколькими галочками быстрее, чем нормальная конкатенация:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));
1
ответ дан samjudson 23 November 2019 в 20:25
поделиться

Я всегда шел строка. Формат () маршрут. Способность сохранить форматы в переменных как пример Nathan является большим преимуществом. В некоторых случаях я могу добавить переменную, но еще раз, чем 1 переменная связывается, я осуществляю рефакторинг для использования форматирования.

1
ответ дан Scott Muc 23 November 2019 в 20:25
поделиться

Мне на самом деле нравится первый потому что, когда существует много переменных, смешиваемых с текстом, который кажется легче прочитать в меня. Плюс, легче иметь дело с кавычками при использовании строки. Формат (), мм, формат. Вот достойный анализ из конкатенации строк.

1
ответ дан adparadox 23 November 2019 в 20:25
поделиться

Лично, второй как все, что Вы используете, находится в прямом порядке, в котором он будет произведен. Принимая во внимание, что с первым необходимо совпасть {0} и {1} с надлежащим var, который легко испортить.

, По крайней мере, это не настолько плохо как C++ sprintf, где, если Вы получаете тип переменной неправильно, все это аварийно завершится.

кроме того, так как второе все встроено, и это не должно делать никакого поиска и замены для весь эти {0} вещи, последний должен быть быстрее..., хотя я не знаю наверняка.

1
ответ дан Adam Haile 23 November 2019 в 20:25
поделиться

Хороший!

Просто добавил

        s.Start();
        for (var i = 0; i < n; i++)
            result = string.Concat(p.FirstName, " ", p.LastName);
        s.Stop();
        ceElapsedMilliseconds = s.ElapsedMilliseconds;
        ceElapsedTicks = s.ElapsedTicks;
        s.Reset();

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

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 249ms - 3571621 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 65ms - 944948 ticks
1000000 x result = string.Concat(p.FirstName, " ", p.LastName); took: 54ms - 780524 ticks
2
ответ дан Philippe 23 November 2019 в 20:25
поделиться

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

2
ответ дан Chuck 23 November 2019 в 20:25
поделиться

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

Выбор правильный инструмент на основе задания: D, Какой бы ни выглядит самым чистым!

2
ответ дан mercutio 23 November 2019 в 20:25
поделиться

Если Вы имеете дело с чем-то, что должно быть легко считать (и это - большая часть кода), я придерживался бы версии перегрузки оператора ЕСЛИ:

  • код должен быть выполняемыми миллионами времен
  • , Вы делаете тонны concats (больше чем 4 - тонна)
  • , код предназначен к Компактной Платформе

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

3
ответ дан plinth 23 November 2019 в 20:25
поделиться
  1. Форматирование является способом “.NET” сделать его. Определенные инструменты рефакторинга (Осуществляют рефакторинг! для одного), даже предложит осуществить рефакторинг код concat-стиля для использования стиля форматирования.
  2. Форматирование легче оптимизировать для компилятора (хотя второе, вероятно, будет пересмотрено для использования метода 'Concat', который быстр).
  3. Форматирование является обычно более четким читать (особенно с форматированием “fancy”).
  4. Форматирование значит неявные вызовы для '.ToString' на всех переменных, который хорош для удобочитаемости.
  5. Согласно “Effective C#”.NET 'WriteLine' и реализации 'Формата' испорчена, они автоупаковывают все типы значения (который плох). “Effective C#” советует для выполнения '.ToString' вызовы явно, который, по моему скромному мнению, является поддельным (см. Jeff отправлять )
  6. В данный момент, форматирующие подсказки типа не проверяются компилятором, приводящим к ошибкам периода выполнения. Однако это могло быть исправлено в будущих версиях.
4
ответ дан Konrad Rudolph 23 November 2019 в 20:25
поделиться

Я поражен, что столько людей сразу хочет найти код, который выполняет самое быстрое. , Если ОДИН МИЛЛИОН повторений ВСЕ ЕЩЕ берет меньше, чем секунда для обработки, будет этим ВСЕГДА примечательным конечному пользователю? Не очень вероятно.

Преждевременная оптимизация = СБОЙ.

я пошел бы с String.Format опция, только потому, что она имеет большую часть смысла с архитектурной точки зрения. Я не забочусь о производительности, пока это не становится проблемой (и если бы это сделало, я спросил бы меня: я должен связать миллион имен сразу? Конечно, они не будут все соответствовать на экране...)

, Рассматривают, хочет ли Ваш клиент позже изменить его так, чтобы они могли настроить, отобразиться ли "Firstname Lastname" или "Lastname, Firstname." С Параметром формата, это легко - просто выгружают строку формата. С concat Вам будет нужен дополнительный код. Уверенный это не походит на грандиозное предприятие в этом конкретном примере, но экстраполирует.

156
ответ дан 4 revs, 4 users 60% 23 November 2019 в 20:25
поделиться

Боже мой - после чтения одного из других ответов я пытался инвертировать порядок операций - настолько работающий конкатенацию сначала, тогда Строка. Формат...

Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 8ms - 30488 ticks
Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 0ms - 182 ticks

, Таким образом, порядок операций имеет Огромное значение, или скорее самая первая операция ВСЕГДА намного медленнее.

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

Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 5ms - 20335 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 156 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 122 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 181 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 122 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 142 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 117 ticks

, Поскольку Вы видите последующие выполнения того же метода (я осуществил рефакторинг код в 3 метода) инкрементно быстрее. Самое быстрое, кажется, Консоль. WriteLine (Строка. Concat (...)) метод, сопровождаемый нормальной конкатенацией, и затем отформатированными операциями.

начальная задержка запуска вероятна инициализация Консольного Потока как размещение Консоли. Writeline ("Запускаются!"), прежде чем первая операция заставляет все случаи подчиняться назад.

54
ответ дан 3 revs 23 November 2019 в 20:25
поделиться

Вот являются мои результаты более чем 100 000 повторений:

Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took (avg): 0ms - 689 ticks
Console.WriteLine(p.FirstName + " " + p.LastName); took (avg): 0ms - 683 ticks

И вот код места размещения:

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

//First print to remove the initial cost
Console.WriteLine(p.FirstName + " " + p.LastName);
Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

int n = 100000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

for (var i = 0; i < n; i++)
{
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();
    cElapsedMilliseconds += s.ElapsedMilliseconds;
    cElapsedTicks += s.ElapsedTicks;
    s.Reset();
    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    fElapsedMilliseconds += s.ElapsedMilliseconds;
    fElapsedTicks += s.ElapsedTicks;
    s.Reset();
}

Console.Clear();

Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took (avg): " + (fElapsedMilliseconds / n) + "ms - " + (fElapsedTicks / n) + " ticks");
Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took (avg): " + (cElapsedMilliseconds / n) + "ms - " + (cElapsedTicks / n) + " ticks");

Так, я не знаю чей ответ отмечать как ответ:)

14
ответ дан 2 revs, 2 users 74% 23 November 2019 в 20:25
поделиться

Я использовал бы Строку. Формат, но у меня также была бы строка формата в файлах ресурсов, таким образом, это может быть локализовано для других языков. Используя простую строку concat не позволяет Вам делать это. Очевидно, если Вы, привычка когда-либо должна локализовать ту строку, это не причина думать о. Это действительно зависит от того, для чего строка.

, Если бы это будет, показал пользователю, я использовал бы Строку. Формат, таким образом, я могу локализовать, если мне нужно к - и FxCop, проверит правописание его для меня на всякий случай:)

, Если бы это содержит числа или какие-либо другие нестроковые вещи (например, даты), я использовал бы Строку. Формат, потому что это дает мне больше управление форматированием .

, Если бы это для создания запроса как SQL, я использовал бы Linq.

, Если бы для конкатенации строк в цикле, я использовал бы StringBuilder для предотвращения проблем производительности.

, Если бы это для некоторого вывода, пользовательская привычка видит, и не собирается производить производительность, я использовал бы Строку. Формат, потому что я имею привычку использовать его так или иначе и я просто привык к нему:)

4
ответ дан 2 revs 23 November 2019 в 20:25
поделиться

Для очень простого управления я использовал бы конкатенацию, но как только Вы добираетесь вне 2 или 3 Форматов элементов, становится более соответствующим IMO.

Другая причина предпочесть Строку. Формат - то, что строки.NET неизменны и делают его, этот путь создает меньше временных/промежуточных копий.

7
ответ дан user2189331 23 November 2019 в 20:25
поделиться

Конкатенация строк прекрасна в простом сценарии как этот - это более сложно с чем-либо более сложным, чем это, даже LastName, FirstName. С форматом Вы видите, сразу, чем заключительная структура строки будет при чтении кода с конкатенацией, кроме которой становится почти невозможно сразу различить конечный результат (с очень простым примером как этот).

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

при использовании.NET 3.5 можно использовать дополнительный метод как этот и получить легкое течение, неподготовленный синтаксис как это:

string str = "{0} {1} is my friend. {3}, {2} is my boss.".FormatWith(prop1,prop2,prop3,prop4);

Наконец, когда Ваше приложение растет в сложности, можно решить, что для нормального поддержания строк в приложении Вы хотите переместить их в файл ресурсов для локализации или просто в статического помощника. Этого будет НАМНОГО легче достигнуть, если Вы последовательно использовали форматы, и Ваш код может быть вполне просто пересмотрен для использования чего-то как

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);
9
ответ дан Nathan 23 November 2019 в 20:25
поделиться

Для основной конкатенации строк я обычно использую второй стиль - легче читать и более простой. Однако, если я делаю более сложную строковую комбинацию, я обычно выбираю Строку. Формат.

Строка. Формат экономит на большом количестве кавычек и плюсов...

Console.WriteLine("User {0} accessed {1} on {2}.", user.Name, fileName, timestamp);
vs
Console.WriteLine("User " + user.Name + " accessed " + fileName + " on " + timestamp + ".");

Только несколько сохраненные charicters, но я думаю в этом примере, формат делает его намного более чистым.

5
ответ дан Mike 23 November 2019 в 20:25
поделиться

Лучший тест должен был бы следить за Вашим использованием памяти Perfmon и счетчики памяти CLR. Мое понимание - то, что целая причина Вы хотите использовать Строку. Формат вместо того, чтобы просто связать строки, так как строки неизменны, Вы излишне обременяете сборщик "мусора" временными строками, которые должны быть исправлены в следующей передаче.

StringBuilder и Строка. Формат, хотя потенциально медленнее, является большей эффективной памятью.

, Что так плохо о конкатенации строк?

5
ответ дан David Hill 23 November 2019 в 20:25
поделиться

Обычно я предпочитаю первого, как особенно, когда строки становятся длинными, может быть намного легче читать.

другое преимущество, я верю одной из производительности, поскольку последний на самом деле выполняет 2 строковых оператора создания прежде, чем передать заключительную строку Консоли. Метод записи. Строка. Формат использует StringBuilder под покрытиями, которым я верю, таким образом, нескольких конкатенаций избегают.

нужно отметить однако это, если параметры Вы являетесь передающими в Представить в виде строки. Формат (и другие такие методы как Консоль. Запишите), типы значения тогда, они будут упакованы, прежде чем передано в, который может обеспечить его собственные хиты производительности. Сообщение в блоге на этом здесь .

5
ответ дан 2 revs 23 November 2019 в 20:25
поделиться

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

Используя следующий код:

    System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();

    var p = new { FirstName = "Bill", LastName = "Gates" };

    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

    s.Reset();
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();

    Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

я получил следующие результаты:

Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 2ms - 7280 ticks
Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 0ms - 67 ticks

Используя метод форматирования более чем в 100 раз медленнее!! Конкатенация даже не зарегистрировалась как 1 мс, который является, почему я произвел галочки таймера также.

6
ответ дан Adam Haile 23 November 2019 в 20:25
поделиться

I choose based on readability. I prefer the format option when there's some text around the variables. In this example:

Console.WriteLine("User {0} accessed {1} on {2}.", 
                   user.Name, fileName, timestamp);

you understand the meaning even without variable names, whereas the concat is cluttered with quotes and + signs and confuses my eyes:

Console.WriteLine("User " + user.Name + " accessed " + fileName + 
                  " on " + timestamp + ".");

(I borrowed Mike's example because I like it)

If the format string doesn't mean much without variable names, I have to use concat:

   Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

The format option makes me read the variable names and map them to the corresponding numbers. The concat option doesn't require that. I'm still confused by the quotes and + signs, but the alternative is worse. Ruby?

   Console.WriteLine(p.FirstName + " " + p.LastName);

Performance wise, I expect the format option to be slower then the concat, since format requires the string to be parsed. I don't remember having to optimize this kind of instruction, but if I did, I'd look at string methods like Concat() and Join().

The other advantage with format is that the format string can be put in a configuration file. Very handy with error messages and UI text.

3
ответ дан 23 November 2019 в 20:25
поделиться

Если вы собираетесь локализовать результат, необходимо использовать String.Format, потому что на разных естественных языках данные могут даже не располагаться в одном и том же порядке.

3
ответ дан 23 November 2019 в 20:25
поделиться

Согласно подготовительному материалу MCSD, Microsoft предлагает использовать оператор + при работе с очень небольшим количеством конкатенаций (вероятно, от 2 до 4). Я до сих пор не знаю почему,

1
ответ дан 23 November 2019 в 20:25
поделиться

Пожалейте бедных переводчиков

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

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

22
ответ дан 23 November 2019 в 20:25
поделиться

На самом деле я вчера запустил эти тесты, но становилось поздно, таким образом, я не помещал свои ответы.

нижняя строка кажется, что они берут обоих то же время в среднем. Я сделал тест более чем 100 000 повторений.

я попробую StringBuilder также, и я отправлю код и результаты, когда я возвращусь домой.

0
ответ дан Philippe 23 November 2019 в 20:25
поделиться
Другие вопросы по тегам:

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