Здравствуйте, Shmj, Вы писали:
S>Здравствуйте, Sharowarsheg, Вы писали:
S>>Она что у тебя там, всего один раз выполняется?
S>Один раз, но строка достаточно длинная.
Нет, нужно в тыщу раз больше, по крайней мере. Кроме того, это разные режимы — один раз и очень длинная строка, или много раз маленькие строки. В любом случае, самый быстрый будет тот, в котором больше всего for int i=0.... и меньше всего всяких прогрессивных LINQ и проча. Не исключено, что еще быстрее будет переделать строку в массив слов Uint16 и с ними работать.
Здравствуйте, adetkov, Вы писали: A>| Method | Mean | Error | StdDev | A>|--------- |----------:|---------:|---------:| A>| Unescape | 74.69 ms | 1.471 ms | 2.063 ms | A>| Test5 | 126.85 ms | 2.401 ms | 2.128 ms |
Странно, у меня другие результаты:
Скрытый текст
Test6=206
Test5=184
Test6=194
Test5=200
Test6=205
Test5=182
Test6=209
Test5=181
Test6=204
Test5=184
Test6=204
Test5=186
Test6=206
Test5=187
Test6=208
Test5=272
Test6=223
Test5=176
Test6=206
Test5=189
Test5 практически всегда быстре.
Полный код:
Скрытый текст
using System;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Random r = new Random();
var sb = new StringBuilder(2000000 * 7);
sb.Append("test1\ntest2\\n\\\\test3");
for (int i = 0; i < 2000000; i++)
{
if (r.Next(1, 3) == 1)
sb.Append("\\");
if (r.Next(1, 3) == 1)
sb.Append("\\");
if (r.Next(1, 3) == 1)
sb.Append("\\n");
if (r.Next(1, 4) == 3)
sb.Append("\n");
sb.Append("word");
}
var input = sb.ToString();
var escaped = input.Replace("\\", "\\\\").Replace("\n", "\\n");
var sw = new Stopwatch();
for (int i = 0; i < 10; i++)
{
sw.Reset();
sw.Start();
Test6(escaped);
sw.Stop();
Console.WriteLine("Test6=" + sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
Test5(escaped);
sw.Stop();
Console.WriteLine("Test5=" + sw.ElapsedMilliseconds);
Console.WriteLine();
}
sw.Reset();
sw.Start();
//var unescaped = Test1(escaped); // 1235
//var unescaped = Test2(escaped); mamma mia!
//var unescaped = Test3(escaped); // 891
//var unescaped = Test4(escaped); // 289
//var unescaped = Test5(escaped); // 183var unescaped = Test6(escaped); // 208
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Console.ReadLine();
Console.WriteLine(unescaped.Equals(input));
}
static string Test1(string escaped)
{
var guid = Guid.NewGuid().ToString();
return escaped.Replace("\\\\", guid).Replace("\\n", "\n").Replace(guid, "\\");
}
static string Test2(string escaped)
{
return escaped.Split(new[] {"\\\\"}, StringSplitOptions.None)
.Aggregate((seed, next) => seed + "\\" + next.Replace("\\n", "\n"));
}
static string Test3(string escaped)
{
var parts = escaped.Split(new[] {"\\\\"}, StringSplitOptions.None)
.Select(part => part.Replace("\\n", "\n"));
return string.Join("\\", parts);
}
static string Test4(string escaped)
{
var unescaped = new StringBuilder(escaped.Length);
bool slash = false;
foreach (var ch in escaped)
{
if (slash)
{
if ('\\' == ch)
unescaped.Append('\\');
if ('n' == ch)
unescaped.Append('\n');
slash = false;
continue;
}
if ('\\' == ch)
slash = true;
else
unescaped.Append(ch);
}
return unescaped.ToString();
}
static string Test5(string escaped)
{
var unescaped = new StringBuilder(escaped.Length);
int currentIndex = 0;
while (true)
{
var slashIndex = escaped.IndexOf('\\', currentIndex);
if (-1 == slashIndex)
{
unescaped.Append(escaped, currentIndex, escaped.Length - currentIndex);
break;
}
unescaped.Append(escaped, currentIndex, slashIndex - currentIndex);
currentIndex = slashIndex;
var nextChar = escaped[slashIndex + 1];
switch (nextChar)
{
case'\\':
unescaped.Append('\\');
break;
case'n':
unescaped.Append('\n');
break;
default:
throw new InvalidOperationException("nextChar=" + nextChar);
}
currentIndex++;
currentIndex++;
}
return unescaped.ToString();
}
private static string Test6(string str)
{
char[] array = str.ToCharArray();
int cur = 0;
bool waitControl = false;
for (int i = 0; i < array.Length; i++)
{
if (!waitControl)
{
if (array[i] == '\\')
{
waitControl = true;
continue;
}
array[cur++] = array[i];
continue;
}
waitControl = false;
switch (array[i])
{
case'n':
array[cur++] = '\n';
break;
case'\\':
array[cur++] = '\\';
break;
default:
throw new Exception("Unexpected control symbol");
}
}
return new string(array, 0, cur);
}
}
}
Здравствуйте, Mystic Artifact, Вы писали:
MA>Здравствуйте, _NN_, Вы писали:
_NN>>Использование Stopwatch не всегда правильно отражает действительность. MA> Что же он по вашему отражает?
Нужно учитывать сборку мусора, прогрев JIT компилятора.
Не забыть запускать релизную сборку правильно. Бывает, что запускают под отладчиком.
Здравствуйте, _NN_, Вы писали:
MA>> Что же он по вашему отражает? _NN>Нужно учитывать сборку мусора, прогрев JIT компилятора. _NN>Не забыть запускать релизную сборку правильно. Бывает, что запускают под отладчиком.
Конечно это всё нужно учитывать и делать правильно. Есть еще масса других вещей которые учесть невозможно или трудно, наподобии влияния ОС, фоновых задач, спрогнозировать степень деградации красивых цифр полученных с помощью любых утилит, навроде бенчмаркдотнет, при увеличении нагрузки/конкуренции.
Вместе с тем, время выполнения — очень легко доступный показатель (и его производные) и к счастью именно оно отражает субьективную реальность, при чем его сильная сторона и она же ахилесова пята, что в него уже включены все затраты: на старт процесса, на JIT, на GC, кол-во перемолотой памяти.
PS: Не нравится Stopwatch — можно взять стрелочный секундомер.
N = количество повторов (в оригинале — 2000000, я сократил).
Scale — это коэффициент уменьшения плотности спецсимволов. В оригинале их напихано очень часто; я проверял, как зависит производительность от их частоты. В пределе, при очень больших Scale, в строке вообще не встречается ни \ ни n, и алгоритм вырождается в тупое копирование строки. При scale = 1 частоты совпадают с исходными.
Вот, собственно, код инициализации:
UnescapeTests()
public UnescapeTests()
{
var sb = new StringBuilder(N * 7);
sb.Append("start:");
for (int i = 0; i < N; i++)
{
if (_r.Next(1, 3 * Scale) == 1)
sb.Append("\\");
if (_r.Next(1, 3 * Scale) == 1)
sb.Append("\\");
if (_r.Next(1, 3 * Scale) == 1)
sb.Append("\\n");
if (_r.Next(1, 4 * Scale) == 1)
sb.Append("\n");
sb.Append("word");
}
_escaped = sb.ToString()
.Replace("\\", "\\\\")
.Replace("\n", "\\n");
}
Понятно, что по соображениям воспроизводимости Random инициализируется константой. (42).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.