[C#] Вопрос о скорости

valkira

Если для программы очень критична производительность, и в ней активно используются очень длинные (порядка нескольких десятков тысяч) массивы данных (например, чисел типа double то что лучше использовать: обычный double[] или генерик ArrayList<double>? Последний гораздо удобнее в плане программирования, но насколько быстро он работает? Помогите советом, пожалуйста.

agent007new

CLR via C# - в этой книге хорошо расписано, что и как нужно делать с массивами, когда нужна производительность

valkira

Спасибо! Понял, что для скорости лучше всего подходит небезопасный код типа:
double[] a = new double[n];
fixed (double* p = &a[0])
{
for (int i = 0; i < n; i++)
{
x = p[i];
}
}

Еще там сказано, что такой способ может привести к разрушению памяти, нарушению безопасности типов и возникновению бреши в защите программы. Может кто-нибудь переведет это на русский язык?

Dasar

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

Dasar

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

SPARTAK3959

К тому же JIT-compiler может сам выкинуть/соптимизировать проверки выхода за границы массива в некоторых случаях. По крайней мере в java это так.

valkira

А про ArrayList<T> вообще что можно сказать в плане производительности?

Dasar

А про ArrayList<T> вообще что можно сказать в плане производительности?
во-первых, такого класса вообще нет, есть List<T>
во-вторых, надо смотреть какие задачи
если задача - постоянно добавлять неопределенное кол-во чисел в коллекцию, то List - будет даже быстрее, чем простая реализация поверх массива
если задача - однажды создав коллекцию чисел потом ее часто использовать, то однозначно будет выигрышнее массив.
если же задача - постоянно добавлять/удалять числа из коллекции, то выигрышной будет уже какая-то более сложная структура данных (чем чисто массив, или List<T>)

evolet

это Рихтера что-ли книга про CLR?

Katya19

При итерации по массиву явный for (int i = 0; i < yourArray.Length; ++i) работает намного быстрее, чем foreach(int yourValue in yourArray). По-видимому, JITter хорошо оптимизирует for, а foreach оставляет с enumerator-ами.

Dasar

При итерации по массиву явный for (int i = 0; i < yourArray.Length; ++i) работает намного быстрее, чем foreach(int yourValue in yourArray). По-видимому, JITter хорошо оптимизирует for, а foreach оставляет с enumerator-ами.
что тестилось?
.net 2.0 release, насколько я помню, выдавал уже одну и ту же скорость,
вот для .net 1.x - да, разница была

Serab

http://serugsandappliedscience.com/blog/2009/7/9/towards-c...
Сомневаюсь, что 9го июля 2009 года пользователь использовал первый .NET
Даже сомневаюсь, что второй.

Dasar

хз, что они там тестировали по твоей ссылке, т.к. кода никакого нет.
но вот такой код выдает одно и тоже время

var arr = Enumerable.Range(0, 10000000).Select(i => i * (2 * (i%2)-1.ToArray;

if (true)
{
var stopwatch = new System.Diagnostics.Stopwatch;

stopwatch.Start;

var sum2 = 0;
foreach (var i in arr)
sum2 += i;

stopwatch.Stop;
Console.WriteLine("{0}:{1}", sum2, stopwatch.Elapsed);
}
if (true)
{
var stopwatch = new System.Diagnostics.Stopwatch;

stopwatch.Start;
var sum = 0;
for (int i = 0; i < arr.Length; ++i)
sum += arr[i];
stopwatch.Stop;
Console.WriteLine("{0}:{1}", sum, stopwatch.Elapsed);
}

5000000:00:00:00.0123099
5000000:00:00:00.0125784
у foreach-а будет больше времени, только если он не может догадаться, что на входе массив
это как раз бывает актуально для linq, т.к. там передается сплошной виртуальный ienumerable, что и мешает foreach-у распознать что на входе был массив.

Serab

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

Dasar

Ну вообще код там есть. Надо пройти по ссылке на "предыдущий пост".
если ты про ссылку http://pastebin.com/d10c04029, то она не рабочая

Serab

А, ок, заходил давно, может и не рабочая уже.

Katya19

Вот вам обновленный код, где все функции на вход получают массив, а не интерфейс — http://pastebin.com/f634d2a28
А вот что у меня при этом получается:
Foreach: mean=0,5000 var=0,0833 time=00:00:01.3586989
LINQ: mean=0,5000 var=0,0833 time=00:00:06.2992598
For: mean=0,5000 var=0,0833 time=00:00:00.8955397
For все еще быстрее, хотя разница не так заметна, как в том случае, если foreach получает на вход IEnumerable<T>

sergeikozyr

а цепепе как?

sylar

Для каких задач ты это "множество элементов" (пусть речь не только о double) использовать собираешься и каким образом ?
Как справедливо отметил :
- если список не изменяется (1 раз создан и дальше используется, фиксированное количество элементов) - то делаешь его как массив (array)
- если по ходу работы изменяется - то списком (list)
- добавлю, что если при этом есть например задача проверки уникальности добавленного значения (то есть задача быстро выяснить принадлежит ли такой-то элемент множеству или нет или быстро получить его) - то разумно будет использовать словать (hashtable/dictionary).
P.S. я насчет производительности array и list никогда не задумывался =)
Типы эти использую скорее для того чтобы подчеркнуть семантику переменной
(изменяется или нет)

agent007new

это Рихтера что-ли книга про CLR?
Ага
Оставить комментарий
Имя или ник:
Комментарий: