, так что это представляется возможным при использовании Extract
:
function getShape(type: T): Extract {}
Невозможно сказать, не зная размера string1
и string2
.
С вызовом к AppendFormat
, это предварительно выделит буфер только когда-то, учитывая длину строки формата и строк, которые будут вставлены и затем свяжут все и вставлять его в буфер. Для очень больших строк это будет выгодно по отдельным вызовам для Append
который мог бы заставить буфер расширяться многократно.
Однако три вызова к Append
мог бы или не мог бы инициировать рост буфера, и та проверка выполнена каждый вызов. Если строки будут достаточно маленькими, и никакое буферное расширение не инициировано, то это будет быстрее, чем вызов к AppendFormat
потому что это не должно будет анализировать строку формата для выяснения, где сделать замены.
Больше данных необходимо для категорического ответа
Нужно отметить, что существует мало обсуждения использования помех Concat
метод на String
класс (использование ответа Jon AppendWithCapacity
напомненный меня об этом). Его результаты испытаний показывают, что, чтобы быть лучшим случаем (принимающий Вас не должны использовать в своих интересах определенный спецификатор формата). String.Concat
делает то же самое, в котором это предопределит длину строк, чтобы связать и предварительно выделить буфер (с немного больше служебным из-за конструкций цикличного выполнения через параметры). Это - производительность, будет сопоставимым с Jon AppendWithCapacity
метод.
Или, просто простой оператор сложения, так как это компилирует в вызов к String.Concat
так или иначе, с протестом, что все дополнения находятся в том же выражении:
// One call to String.Concat.
string result = a + b + c;
НЕТ
// Two calls to String.Concat.
string result = a + b;
result = result + c;
Для всех те, которые поднимают тестовый код
Необходимо выполнить тестовые сценарии в отдельных выполнениях (или по крайней мере, выполнить GC между измерением отдельных тестовых прогонов). Причина этого - это, если Вы действительно говорите, 1 000 000 выполнений, создавая новое StringBuilder
в каждом повторении цикла для одного теста, и затем Вы запускаете следующий тест, который циклично выполняет то же количество раз, создавая еще 1 000 000 StringBuilder
экземпляры, GC больше, чем, вероятно, вступит во время второго теста и препятствует своей синхронизации.
casperOne корректен. После того как Вы достигаете определенного порога, Append()
метод становится медленнее, чем AppendFormat()
. Здесь различные длины и протекли галочки 100 000 повторений каждого метода:
Append() - 50900
AppendFormat() - 126826
Append() - 1241938
AppendFormat() - 1337396
Append() - 12482051
AppendFormat() - 12740862
Append() - 61029875
AppendFormat() - 60483914
Когда строки с длиной около 20,000 представлены, AppendFormat()
функция немного превзойдет по характеристикам Append()
.
Почему это происходит? См. ответ casperOne.
Править:
Я повторно выполнил каждый тест индивидуально в соответствии с конфигурацией Выпуска и обновил результаты.
casperOne совершенно точен, что он зависит от данных. Однако предположите запись этого как библиотеки классов для третьих сторон для потребления - который Вы использовали бы?
Одна опция состояла бы в том, чтобы добраться, лучший из обоих миров - удаются, сколько данных Вы на самом деле оказываетесь перед необходимостью добавлять и затем использовать StringBuilder. EnsureCapacity для проверки нам только нужен единственный буфер, изменяют размер.
Если бы я был не слишком побеспокоен, хотя, я использовал бы Append
x3 - это кажется "более вероятным", чтобы быстрее, как проанализировать маркеры формата строки на каждом вызове, ясно делать-работа.
Обратите внимание, что я попросил у команды BCL своего рода "кэшируемого средства форматирования", которое мы могли создать использование строки формата и затем повторного использования неоднократно. Является сумасшедшим, что платформа должна проанализировать строку формата каждый раз, когда это используется.
Править: Хорошо, я отредактировал код John's несколько для гибкости и добавил "AppendWithCapacity", который просто разрабатывает необходимую способность сначала. Вот результаты для различных длин - для длины 1 я использовал 1 000 000 повторений; для всех других длин я использовал 100,000. (Это должно было только получить разумное время выполнения.) Все случаи находятся в millis.
К сожалению, таблицы действительно не работают в ТАК. Длины равнялись 1, 1000, 10000, 20000
Времена:
Таким образом, как это произошло, я никогда не видел, что удар AppendFormat Добавил - но я действительно видел победу AppendWithCapacity очень высокой маржей.
Вот полный код:
using System;
using System.Diagnostics;
using System.Text;
public class StringBuilderTest
{
static void Append(string string1, string string2)
{
StringBuilder sb = new StringBuilder();
sb.Append(string1);
sb.Append("----");
sb.Append(string2);
}
static void AppendWithCapacity(string string1, string string2)
{
int capacity = string1.Length + string2.Length + 4;
StringBuilder sb = new StringBuilder(capacity);
sb.Append(string1);
sb.Append("----");
sb.Append(string2);
}
static void AppendFormat(string string1, string string2)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}----{1}", string1, string2);
}
static void Main(string[] args)
{
int size = int.Parse(args[0]);
int iterations = int.Parse(args[1]);
string method = args[2];
Action<string,string> action;
switch (method)
{
case "Append": action = Append; break;
case "AppendWithCapacity": action = AppendWithCapacity; break;
case "AppendFormat": action = AppendFormat; break;
default: throw new ArgumentException();
}
string string1 = new string('x', size);
string string2 = new string('y', size);
// Make sure it's JITted
action(string1, string2);
GC.Collect();
Stopwatch sw = Stopwatch.StartNew();
for (int i=0; i < iterations; i++)
{
action(string1, string2);
}
sw.Stop();
Console.WriteLine("Time: {0}ms", (int) sw.ElapsedMilliseconds);
}
}
Append
будет быстрее в большинстве случаев, потому что существует много перегрузок к тому методу, которые позволяют компилятору называть корректный метод. Так как Вы используете Strings
StringBuilder
может использовать String
перегрузка для Append
.
AppendFormat
берет a String
и затем Object[]
что означает, что формат должен будет быть проанализирован и каждый Object
в массиве должен будет быть ToString'd
прежде чем это сможет быть добавлено к StringBuilder's
внутренний массив.
Примечание: К точке casperOne - трудно дать точный ответ без большего количества данных.
StringBuilder
также расположился каскадом, добавляет: Append()
возвраты StringBuilder
самостоятельно, таким образом, можно написать код как это:
StringBuilder sb = new StringBuilder();
sb.Append(string1)
.Append("----")
.Append(string2);
Чистый, и это генерирует меньше IL-кода (хотя это - действительно микрооптимизация).
Конечно, профиль для знания наверняка в каждом случае.
Тем не менее я думаю в целом, что это будет первый, потому что Вы неоднократно не анализируете строку формата.
Однако разница была бы очень небольшой. До такой степени, что действительно необходимо рассмотреть использование AppendFormat
в большинстве случаев так или иначе.
Я предположил бы, что это был вызов, который сделал наименьшее количество объема работы. Добавьте просто связывает строки, где AppendFormat делает строковые замены. Конечно, в эти дни Вы никогда не можете говорить...
1 должен быть более быстрый becuase, он просто добавляет строки, тогда как 2 должен создать строку на основе формата и затем добавить строку. Таким образом, существует дополнительный шаг там.
Быстрее 1 в Вашем случае однако, это не справедливое сравнение. Необходимо спросить StringBuilder.AppendFormat()
по сравнению с StringBuilder.Append(string.Format())
- где первый происходит быстрее из-за внутренней работы с массивом символов.
Ваша вторая опция более читаема все же.