Оптимизации C# или тяжёлые будни новичка

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

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

Я пользуюсь C# для написания простого процедурного кода, что-то посчитать, что-то проверить из алгоритмов. Глубоко C# не изучаю, так как мне это неинтересно совсем, пользуюсь им исключительно как молотком чтобы забить саморез - жёстко, абсолютно говнокодисто и с подрывом пятых точек некоторых кодер-наци. Но при этом я знаю, что у любого компилятора могут быть как фиксированные так и настраиваемые оптимизации - ну там переменную в регистр запихать или вместо вызова инлайн код использовать. В общем это понятно и оно есть и к C# у меня отношение как к весьма современному и технологичному продукту и тут мы подбираемся к проблеме, с которой я столкнулся.

Изучая статью я, как и привык, делал замеры времени выполнения кода, причём весьма простым и тривиальным Stopwatch. Если необходимо, то я делаю например 100 проходов и замеряю среднее время, но как правило 2-3 запусков достаточно чтобы определить порядок изменения скорости.

Вот код:

        static long NotDicSearch(byte[] text, byte[] pat)
        {
            int s = 0;
            int compares = 0, jumps = 0, m = pat.Length, n = text.Length, matches = 0, m_1 = m - 1;
            byte[] rights = new byte[256];
            for (int i = 0; i < 256; i++)
                rights[i] = 0;
            for (int i = 0; i < m; i++)
                rights[pat[i]] = 1;
            int[] bpos = new int[m + 1];
            int[] shift = new int[m + 1];
            for (int i = 0; i < m + 1; i++) shift[i] = 0;
            suffix(shift, bpos, pat, m);
            shifts(shift, bpos, pat, m);
            Stopwatch sw = new Stopwatch();
            sw.Restart();
            //------------------------------------------------------------------------------
            while (s <= n - m)
            {
                int j = m - 1;
                while (j >= 0 && text[s + j] == pat[j])
                    j--;
                compares += m - j;
                if (j < 0)
                {
                    matches++;
                    s += m;
                }
                else
                {
                    if (rights[text[s + j]] == 1) s += shift[j + 1];
                    else s += j + 1;
                }
                jumps++;
            }
            //------------------------------------------------------------------------------
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }
        static void suffix(int[] shift, int[] bpos, byte[] pat, int m)
        {
            // m is the length of pattern 
            int i = m, j = m + 1;
            bpos[i] = j;
            while (i > 0)
            {
                while (j <= m && pat[i - 1] != pat[j - 1])
                {
                    if (shift[j] == 0) shift[j] = j - i;
                    j = bpos[j];
                }
                i--; j--;
                bpos[i] = j;
            }
        }
        static void shifts(int[] shift, int[] bpos, byte[] pat, int m)
        {
            int i, j = bpos[0];
            for (i = 0; i <= m; i++)
            {
                if (shift[i] == 0) shift[i] = j;
                if (i == j) j = bpos[j];
            }
        }

Так я провожу вызов:

byte[] text = File.ReadAllBytes("c:\text.txt");
byte[] pat = File.ReadAllBytes("c:\pattern.txt");
long mid = 0;
int i = 0;
for (i = 0; i < 100; i++)
{
    long r = NotDicSearch(text, pat);
    mid = i == 0 ? r : (mid + r) / 2;
}
Console.WriteLine("NaiveStrFind: {0} ms / {1}", mid, i);

Файл размером в 833Мб (выжимка слов из файла enwik9), а паттерн слово "schemata".

Ну и собственно из-за чего сыр-бор - изменение положения строки

int s = 0;

на первую в процедуре (на полном листинге выше как раз в этой позиции) или на позицию перед while

int s = 0;
while (s <= n - m)

меняет скорость работы основного цикла на 7,5% (объявление сразу перед while быстрее) и вопрос - почему оптимизации, такие очевидные как например итератор основного цикла в регистре ЦПУ (если это и происходит с s) зависят от положения строки инициализации переменной в процедуре? И второй очевидный вопрос - сколько таких "приколов" есть еще, чтобы уже знать и выбирать сообразно потребности?

Проверялось на:

Microsoft Visual Studio Community 2022 Версия 17.2.4
VisualStudio.17.Release/17.2.4+32602.215
Microsoft .NET Framework Версия 4.8.04161

Источник: https://habr.com/ru/post/671632/


Интересные статьи

Интересные статьи

Как ускорить 1С БИТРИКС и снизить кол-во запросов к БД используя ядро D7.Пример выборки элементов IBlock с пользовательскими свойствами в один запрос.
Решения для больших компаний обычно должны выдерживать высокие нагрузки. Когда в штате много десятков тысяч человек, и значительная доля из них ежедневно пользуются ...
Я начинающий JS front-end разработчик. Сейчас я учусь и стажируюсь в одной минской IT компании. Изучение основ web-ui проходит на примере JS библиотеки Webix и я хочу поделиться своим первым ...
Ранее в одном из наших КП добавление задач обрабатывалось бизнес-процессами, сейчас задач стало столько, что бизнес-процессы стали неуместны, и понадобился инструмент для массовой заливки задач на КП.
Основанная в 1998 году компания «Битрикс» заявила о себе в 2001 году, запустив первый в России интернет-магазин программного обеспечения Softkey.ru.