Здравствуйте, mr Pink, Вы писали:
MP>Имею три банальных варианта подсчёта символа в строке на C#. MP>Помогите понять, почему третий, самый "тупой" способ "в лоб" работает быстрее всего. MP>[code]
Как меряли скорость?
P.S. Если вы уберете lock, он будет работать еще быстрее
Re[2]: Производительность при поиске символа в строке C#
Здравствуйте, tlp, Вы писали:
tlp>Как меряли скорость?
Через System.Diagnostics.Stopwatch
tlp>P.S. Если вы уберете lock, он будет работать еще быстрее
А смысл?
Re[3]: Производительность при поиске символа в строке C#
Здравствуйте, mr Pink, Вы писали:
MP>Здравствуйте, tlp, Вы писали:
tlp>>Как меряли скорость? MP>Через System.Diagnostics.Stopwatch
покажите, пожалуйста, весь код для тестирования скорости.
tlp>>P.S. Если вы уберете lock, он будет работать еще быстрее MP>А смысл?
Вам не нужно, чтобы быстрее?
Re[4]: Производительность при поиске символа в строке C#
Здравствуйте, koandrew, Вы писали:
K>Здравствуйте, tlp, Вы писали:
tlp>>Вам не нужно, чтобы быстрее?
K>Главное вместе с водой ребёнка не выплеснуть В смысле заменить ++ на соответствующую атомарную операцию.
а в третьем примере к result еще из других потоков обращаются?? Из кода не видно. А если не обращаются, то и лок не нужен
Re[6]: Производительность при поиске символа в строке C#
Здравствуйте, Jack128, Вы писали:
J>а в третьем примере к result еще из других потоков обращаются?? Из кода не видно. А если не обращаются, то и лок не нужен
Ну я исхожу из того, что он там не для красоты стоит. Хотя при длинной входной строке думаю второй вариант быстрее будет, и там либо лок, либо атомарный ++ необходим.
Здравствуйте, koandrew, Вы писали:
K>Здравствуйте, Jack128, Вы писали:
J>>а в третьем примере к result еще из других потоков обращаются?? Из кода не видно. А если не обращаются, то и лок не нужен
K>Ну я исхожу из того, что он там не для красоты стоит.
Ну если не для красоты, то для чего???
K>Хотя при длинной входной строке думаю второй вариант быстрее будет, и там либо лок, либо атомарный ++ необходим.
выделенное очень спорно. я бы вообще сказал, что на любых строках второй вариант будет медленнее третьего (без лока)
Re[6]: Производительность при поиске символа в строке C#
Здравствуйте, Jack128, Вы писали:
J>Здравствуйте, koandrew, Вы писали:
K>>Здравствуйте, tlp, Вы писали:
Так. Друзья, вы на свои вопрос отвечаете.
Вопрос чисто академический и попытка разобраться на базовом примере "как это работает"
var resultList = new List<string>();
int result=0;
var lockObj = new object();
var timer = new System.Diagnostics.Stopwatch();
var inputString = @"<длинная строчка>";
for (var i = 0; i < 20; i++)
{
timer.Start();
<метод>
timer.Stop();
resultList.Add(result.ToString()+" - "+timer.Elapsed.TotalMilliseconds);
timer.Reset();
result = 0;
}
resultList.ForEach(x => Console.WriteLine(x));
Console.ReadKey();
Re[8]: Производительность при поиске символа в строке C#
Здравствуйте, Jack128, Вы писали:
J>Здравствуйте, koandrew, Вы писали:
K>>Здравствуйте, Jack128, Вы писали:
J>>>а в третьем примере к result еще из других потоков обращаются?? Из кода не видно. А если не обращаются, то и лок не нужен
K>>Ну я исхожу из того, что он там не для красоты стоит. J>Ну если не для красоты, то для чего???
K>>Хотя при длинной входной строке думаю второй вариант быстрее будет, и там либо лок, либо атомарный ++ необходим. J>выделенное очень спорно. я бы вообще сказал, что на любых строках второй вариант будет медленнее третьего (без лока)
Уберите локи, чтоб не заострять на них внимание. Всё равно распределение inputString.AsParallel > inputString.Count > цикл
Re[8]: Производительность при поиске символа в строке C#
Здравствуйте, Jack128, Вы писали: J>выделенное очень спорно. я бы вообще сказал, что на любых строках второй вариант будет медленнее третьего (без лока)
Да, вы правы. Я только что проверил:
Код
class Program
{
private static int Method1(string str, char symbol)
{
var result = 0;
str.AsParallel().ForAll(x =>
{
if (x == symbol)
{
Interlocked.Add(ref result, 1);
//result++;
}
});
return result;
}
private static int Method2(string str, char symbol)
{
var result = 0;
Action<char> lambda = x =>
{
if (x == symbol)
{
//Interlocked.Add(ref result, 1);
result++;
}
};
foreach (var @char in str)
{
lambda(@char);
}
return result;
}
static void Main(string[] args)
{
string str = File.ReadAllText("Толстой Лев. Война и мир. Том 1 - royallib.ru.txt");
var res1 = Method1(str, 'a');
var res2 = Method2(str, 'a');
var sw = new Stopwatch();
sw.Restart();
res1 = Method1(str, 'a');
sw.Stop();
Console.WriteLine("Result {0}, time {1}", res1, sw.ElapsedMilliseconds);
sw.Restart();
res2 = Method2(str, 'a');
sw.Stop();
Console.WriteLine("Result {0}, time {1}", res1, sw.ElapsedMilliseconds);
//1.ToString();
}
}
Result 1920, time 9
Result 1920, time 2
Заодно выяснил, что в тексте первого тома "Войны и мир" английская буква "а" встречается ровно 1920 раз
Здравствуйте, mr Pink, Вы писали:
MP>Имею три банальных варианта подсчёта символа в строке на C#. MP>Помогите понять, почему третий, самый "тупой" способ "в лоб" работает быстрее всего.
Welcome to the real world, Luke!
Этот вопрос отлично демонстрирует, что надо очень хорошо понимать ЧТО стоит за модными конструкциями.
И, та-ки, первый вариант можно сделать абсолютно равным по перфомансу третьему (по модулю lock'а) написав нужный extension
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Re[2]: Производительность при поиске символа в строке C#
Здравствуйте, xvost, Вы писали:
X>Здравствуйте, mr Pink, Вы писали:
MP>>Имею три банальных варианта подсчёта символа в строке на C#. MP>>Помогите понять, почему третий, самый "тупой" способ "в лоб" работает быстрее всего.
X>Welcome to the real world, Luke!
X>Этот вопрос отлично демонстрирует, что надо очень хорошо понимать ЧТО стоит за модными конструкциями.
X>И, та-ки, первый вариант можно сделать абсолютно равным по перфомансу третьему (по модулю lock'а) написав нужный extension
Хм. Я нашёл, как сравнять второй и третий (AsParallel и простой цикл). Нужно только привести строку в ToList заранее, ведь это делает AsPаrallel на каждой итерации.
Но вот над Count нужно колдовать как-то иначе. Все равно проигрывает примерно в 10 раз. Какой Extension?
Re: Производительность при поиске символа в строке C#
Если хочется параллельно, то не нужно делать синхронизацию на каждой итерации (пусть даже если это atomic) — в каждом потоке пусть будет свой счётчик, а в конце сложить их в один. Причём эти счётчики нужно разнести по разным cache-line, чтобы избежать false-sharing.
Думаю для C# должен быть уже готовый parallel reduce/accumulate, который сделает всё это автоматом.
Что же касается сильного abstraction penalty — то это же C#, от этого penalty никуда не деться. Если же хочется использовать высокоуровневые конструкции, и при этом получать код аналогичный по скорости низкоуровневым "ручным циклам" — то нужно брать C++
Re[7]: Производительность при поиске символа в строке C#
Здравствуйте, mr Pink, Вы писали:
MP>Здравствуйте, Jack128, Вы писали:
J>>Здравствуйте, koandrew, Вы писали:
K>>>Здравствуйте, tlp, Вы писали:
MP>Так. Друзья, вы на свои вопрос отвечаете. MP>Вопрос чисто академический и попытка разобраться на базовом примере "как это работает"
ну все очень просто:
параллельный код делает очень много дополнителньых операций вроде менеджменда тредов в тредпуле и перекладывания результатов туда-сюда.
Плюс вы добавили lock в многопоточный код превратив его, по сути в однопоточный с дополнительной нагрузкой в виде работы с тредами.
.Count работает медленнее скорее всего потому что оптимизатор не смог достаточно хорошо его оптимизировать и он развернулся в создание списков из строки и вызов дополнтелньых функций вместо их инлайнинга.
Трретий пример лишен всех перечисленых недостатков
Re[3]: Производительность при поиске символа в строке C#
Здравствуйте, koandrew, Вы писали: K>Здравствуйте, Jack128, Вы писали: J>>выделенное очень спорно. я бы вообще сказал, что на любых строках второй вариант будет медленнее третьего (без лока) K>Да, вы правы. Я только что проверил: K>
Код
K>
class Program
K> {
K> private static int Method1(string str, char symbol)
K> {
K> var result = 0;
K> str.AsParallel().ForAll(x =>
K> {
K> if (x == symbol)
K> {
K> Interlocked.Add(ref result, 1);
K> //result++;
K> }
K> });
K> return result;
K> }
K> private static int Method2(string str, char symbol)
K> {
K> var result = 0;
K> Action<char> lambda = x =>
K> {
K> if (x == symbol)
K> {
K> //Interlocked.Add(ref result, 1);
K> result++;
K> }
K> };
K> foreach (var @char in str)
K> {
K> lambda(@char);
K> }
K> return result;
K> }
K> static void Main(string[] args)
K> {
K> string str = File.ReadAllText("Толстой Лев. Война и мир. Том 1 - royallib.ru.txt");
K> var res1 = Method1(str, 'a');
K> var res2 = Method2(str, 'a');
K> var sw = new Stopwatch();
K> sw.Restart();
K> res1 = Method1(str, 'a');
K> sw.Stop();
K> Console.WriteLine("Result {0}, time {1}", res1, sw.ElapsedMilliseconds);
K> sw.Restart();
K> res2 = Method2(str, 'a');
K> sw.Stop();
K> Console.WriteLine("Result {0}, time {1}", res1, sw.ElapsedMilliseconds);
K> //1.ToString();
K> }
K> }
K>
K>
Result 1920, time 9
K>Result 1920, time 2
K>Заодно выяснил, что в тексте первого тома "Войны и мир" английская буква "а" встречается ровно 1920 раз
Только там не английская, а французская
Re[10]: Производительность при поиске символа в строке C#
Здравствуйте, xvost, Вы писали:
X>Здравствуйте, mr Pink, Вы писали:
MP>>Имею три банальных варианта подсчёта символа в строке на C#. MP>>Помогите понять, почему третий, самый "тупой" способ "в лоб" работает быстрее всего.
X>Welcome to the real world, Luke!
X>Этот вопрос отлично демонстрирует, что надо очень хорошо понимать ЧТО стоит за модными конструкциями.