От чего так упала скорость?

213
13 февраля 2018, 05:19

Добрый день, вопрос скорее теоретический, но очень интересно от чего так получилось. И если есть предложения, то как бы убыстрить новообразованный код.

Код буду предоставлять без подробностей реализации, дело не в них и так читать удобнее.

Я создаю файлы основываясь на других файлах. Способ который был до снижения скорости, но были проблемы с памятью представлен далее. Если в двух словах, то я считывал один файл, создавал на его основе сразу же 20 - 50 списков (для каждого нового файла) и хранил их в ассоциативном массиве, после наступления определенного условия, часть из списков сохранялась в файл и удалялась из массива. Но они сильно накапливались и пришлось отказаться от этого из за ошибки недостаточности памяти Основные интересующие меня в данном вопросе процедуры представлены ниже:

    delegate double ToDouble(string num);
delegate void DataManager(MqlTick tick,
                          string key,
                          ref SortedList<string, List<MqlTick>> tickData,
                          ref SortedList<string, List<MqlRates>> ratesData,
                          ref bool addRow);
delegate double SmileToPrice(smileData IV_data, double strike, bool isCall);
delegate void CheckDirectories(string pathToFolder, string dirName);
delegate string WriteConverter<T>(T Data);
class Converter
{
    public void createQuotes(inputData data)
    {
        // запускаем создание файлов
    }
    private DateTime getExpiryMonth(string futName)
    {
        // Получаем дату из переданой строки
    }
    private List<QuotesDetales> fileReader(ref SortedList<string, List<MqlTick>> tickData,
                                    ref SortedList<string, List<MqlRates>> ratesData,
                                    inputData data,
                                    DateTime DT_border,
                                    string selectedFile,
                                    DateTime fileMonth,
                                    ref Dictionary<string, List<double>> strikeCollection)
    {
        List<QuotesDetales> expiredAssets // устанавливаю
        // Select asset by dates
        DateTime start // устанавливаю
        DateTime end = // устанавливаю
        // String to double
        ToDouble strToDouble = (string num) =>
       {
           // Преобразовываем число из строки в double (часть файлов с запятыми, часть с точками ввиде разделителя идут)
       };
        // Add data
        DataManager addData = (MqlTick tick,
                               string key,
                               ref SortedList<string, List<MqlTick>> ticks,
                               ref SortedList<string, List<MqlRates>> rates,
                               ref bool addRow) =>
       {
           // Заполняем tickData и ratesData (переданые по ссылкам как ticks и rates)
       };
        // Calculation price
        SmileToPrice getPrice = (smileData IV_data, double strike, bool isCall) =>
        {
            // Считаем значение цены
        };
        // reading file
        using (StreamReader reader = File.OpenText(selectedFile))
        {
            reader.ReadLine();
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if (!string.IsNullOrEmpty(line) && !string.IsNullOrWhiteSpace(line))
                {
                    string[] thisLine = line.Split(';');
                    DateTime expiryMonth = getExpiryMonth(thisLine[0]);
                    if (thisLine[0].Substring(0, data.mask.Length).CompareTo(data.mask) == 0 &&
                        expiryMonth.CompareTo(start) >= 0 && expiryMonth.CompareTo(end) <= 0)
                    {
                        DateTime currentDT = DateTime.ParseExact(thisLine[2], "yyyyMMddHHmmssfff", null);
                        if (strToDouble(thisLine[4]) != 0 &&
                            strToDouble(thisLine[10]) > 0 &&
                            currentDT.CompareTo(data.from) >= 0)
                        {
                            smileData IV_data = new smileData
                            {
                                Price = strToDouble(thisLine[3]),
                                A = strToDouble(thisLine[5]),
                                B = strToDouble(thisLine[6]),
                                C = strToDouble(thisLine[7]),
                                D = strToDouble(thisLine[8]),
                                E = strToDouble(thisLine[9]),
                                S = strToDouble(thisLine[4]),
                                T = strToDouble(thisLine[10])
                            };
                            List<double> strikes = new List<double>();
                            if (strikeCollection.ContainsKey(thisLine[0]))
                                strikes = strikeCollection[thisLine[0]];
                            else
                                strikeCollection.Add(thisLine[0], strikes);
                            getStrike(IV_data.Price, data.stepStrikes, data.numStrikes, ref strikes);
                            strikeCollection[thisLine[0]] = strikes;
                            MqlTick tick = new MqlTick
                            {
                                time = currentDT,
                                volume = 0
                            };
                            bool addRow = false;
                            foreach (double K in strikes)
                            {
                                for (int i = 0; i < 2; i++)
                                {
                                    tick.last = getPrice(IV_data, K, (i == 0 ? true : false));
                                    tick.bid = tick.last;
                                    tick.ask = tick.last;
                                    if (data.spreadBidAsk > 0)
                                    {
                                        // Делаем еще некоторые действия с преобразованием цены
                                    }
                                    string key = thisLine[0] + "_" + (i == 0 ? "Call" : "Put") + "_" + K.ToString();
                                    addData(tick, key, ref tickData, ref ratesData, ref addRow); // Передаем в лямбду на заполнение структуры
                                    QuotesDetales detales_current = new QuotesDetales
                                    {
                                        assetName = key,
                                        isCall = (i == 0 ? true : false),
                                        strike = K
                                    };
                                    if (fileMonth.CompareTo(expiryMonth) >= 0 &&
                                        expiredAssets.FindAll(x => x.assetName == detales_current.assetName).Count == 0)
                                        expiredAssets.Add(detales_current);
                                }
                            }
                        }
                    }
                }
            }
        }
        return expiredAssets;
    }
    private void getStrike(double Price, double Step, int num, ref List<double> ans)
    {
       // Получаем список Double который далее будем перебирать
    }
    private void fileWriter(ref SortedList<string, List<MqlTick>> tickData,
                            ref SortedList<string, List<MqlRates>> ratesData,
                            ref List<QuotesDetales> assetsToWrite,
                            DateTime endDate,
                            string pathToFolder)
    {
        WriteConverter<MqlTick> writeData_tick = (MqlTick tick) =>
        {
            // сткукрута в строку
        };
        WriteConverter<MqlRates> writeData_rates = (MqlRates rate) =>
        {
            // сткукрута в строку
        };
        for (int i = 0; i < assetsToWrite.Count; i++)
        {
            QuotesDetales item = assetsToWrite[i];
            item.expiration = tickData[item.assetName].Max(x => x.time);
            assetsToWrite[i] = item;
            Writer(pathToFolder + "\\TickData\\" + item.assetName + ".csv", tickData[item.assetName], writeData_tick, "<DATE>\t<TIME>\t<BID>\t<ASK>\t<LAST>\t<VOLUME>");
            tickData.Remove(item.assetName);
            Writer(pathToFolder + "\\CandleData\\" + item.assetName + ".csv", ratesData[item.assetName], writeData_rates, "<DATE>\t<TIME>\t<OPEN>\t<HIGH>\t<LOW>\t<CLOSE>\t<TICKVOL>\t<VOL>\t<SPREAD>");
            ratesData.Remove(item.assetName);
        }
    }
    private void Writer<T>(string path, List<T> Data, WriteConverter<T> converter, string headdder)
    {
        // пишу в файл
    }

Я переписал этот код следующим образом, проблема с памятью вроде исчезла, но на что на что у первого варианта уходил час - два, у второго уходит пол дня... И я не пойму от чего так.

Если в вкратце, то переписанный вариант, не накапливает создаваемые мною файлы, а накапливает только лишь исходную информацию для создания файлов, ее намного меньше и памяти занимает она тоже меньше. Затем при наступлении определенного условия, разом создаю требуемые списки и сохраняю их в файлы, далее память отчищается так как эти списки хранятся в локальных переменных. функции "fileWriter" Код ниже:

public delegate double ToDouble(string num);
delegate void DataManager(MqlTick tick,
                          string key,
                          ref Dictionary<string, List<MqlTick>> tickData,
                          ref Dictionary<string, List<MqlRates>> ratesData,
                          ref bool addRow,
                          ref DateTime DT);
delegate double SmileToPrice(smileData IV_data, double strike, bool isCall);
delegate void CheckDirectories(string pathToFolder, string dirName);
delegate string WriteConverter<T>(T Data);
class Converter
{
    public Converter(HistoryCreator mainWindow)
    {
        this.mainWindow = mainWindow;
        max = 0;
        fileName = "";
        provider = new NumberFormatInfo();
        provider.NumberDecimalSeparator = ".";
        cond = mainWindow.showReadingLine;
    }
    HistoryCreator mainWindow;
    int max;
    string fileName;
    private NumberFormatInfo provider;
    private bool cond;
    public void createQuotes(inputData data)
    {
       // запускаем создание файлов
    }
    private DateTime getExpiryMonth(string futName)
    {
      // Получаем дату из переданой строки
    }
    private List<string> fileReader(ref Dictionary<string, List<smileData>> smileTickData,
                                    inputData data,
                                    string selectedFile,
                                    DateTime fileMonth)
    {
        List<string> expiredAssets // устанавливаю
        // Select asset by dates
        DateTime start // устанавливаю
        DateTime end // устанавливаю
        // String to double
        ToDouble strToDouble = (string num) =>
        {
            // Преобразовываем число из строки в double (часть файлов с запятыми, часть с точками ввиде разделителя идут)
        };
        // reading file
        using (StreamReader reader = File.OpenText(selectedFile))
        {
            mainWindow.Invoke(mainWindow.pbUpdater, new object[] { false, max, fileName, "Чтение файла", true });
            reader.ReadLine();
            string line;
            int c = 1;
            while ((line = reader.ReadLine()) != null)
            {
                if (mainWindow.showReadingLine)
                {
                    if (!cond) cond = true;
                    mainWindow.Invoke(mainWindow.pbUpdater, new object[] { false, max, fileName, "Чтение файла Строка №" + c.ToString(), false });
                    c++;
                }
                else if (cond)
                {
                    cond = false;
                    mainWindow.Invoke(mainWindow.pbUpdater, new object[] { false, max, fileName, "Чтение файла", false });
                }
                if (!string.IsNullOrEmpty(line) && !string.IsNullOrWhiteSpace(line))
                {
                    string[] thisLine = line.Split(';');
                    DateTime expiryMonth = getExpiryMonth(thisLine[0]);
                    if (thisLine[0].Substring(0, data.mask.Length).CompareTo(data.mask) == 0 &&
                        expiryMonth.CompareTo(start) >= 0 && expiryMonth.CompareTo(end) <= 0)
                    {
                        DateTime currentDT = DateTime.ParseExact(thisLine[2], "yyyyMMddHHmmssfff", null);
                        if (strToDouble(thisLine[4]) != 0 &&
                            strToDouble(thisLine[10]) > 0 &&
                            currentDT.CompareTo(data.from) >= 0)
                        {
                            smileData IV_data = new smileData
                            {
                                Price = strToDouble(thisLine[3]),
                                A = strToDouble(thisLine[5]),
                                B = strToDouble(thisLine[6]),
                                C = strToDouble(thisLine[7]),
                                D = strToDouble(thisLine[8]),
                                E = strToDouble(thisLine[9]),
                                S = strToDouble(thisLine[4]),
                                T = strToDouble(thisLine[10]),
                                currentDT = currentDT
                            };
                            if (!smileTickData.ContainsKey(thisLine[0]))
                                smileTickData.Add(thisLine[0], new List<smileData>());
                            smileTickData[thisLine[0]].Add(IV_data);
                            if (fileMonth.CompareTo(expiryMonth) >= 0 &&
                                !expiredAssets.Contains(thisLine[0]))
                                expiredAssets.Add(thisLine[0]);
                        }
                    }
                }
            }
        }
        return expiredAssets;
    }
    private void getStrike(double Price, double Step, int num, ref List<double> ans)
    {
       // Получаем список Double который далее будем перебирать
    }
    private List<QuotesDetales> fileWriter(ref Dictionary<string, List<smileData>> smileTickData,
                                           List<string> assetsToWrite,
                                           inputData data,
                                           ref DateTime DT)
    {
        string pathToFolder = data.pathToFolder + "\\Result\\" + data.resultDirName;
        List<QuotesDetales> fileDetales = new List<QuotesDetales>();
        WriteConverter<MqlTick> writeData_tick = (MqlTick tick) =>
        {
            // структура в строку
        };
        WriteConverter<MqlRates> writeData_rates = (MqlRates rate) =>
        {
           // структура в строку
        };
        WriteConverter<smileData> writeData_smileParams = (smileData smile) =>
        {
           // структура в строку
        };
        SmileToPrice getPrice = (smileData IV_data, double strike, bool isCall) =>
        {
            // Считаем значение цены
        };
        // Add data
        DataManager addData = (MqlTick tick,
                               string key,
                               ref Dictionary<string, List<MqlTick>> ticks,
                               ref Dictionary<string, List<MqlRates>> rates,
                               ref bool addRow,
                               ref DateTime DT_border) =>
        {
           // Заполняем tickData и rateData (переданые по ссылкам как ticks и rates)
        };
        mainWindow.Invoke(mainWindow.pbUpdater, new object[] { false, max, fileName, "Создание котировок", false });
        if (assetsToWrite.Count > 0)
        {
            foreach (string key in assetsToWrite)
            {
                List<double> strikes = new List<double>();
                Dictionary<string, List<MqlTick>> tickData = new Dictionary<string, List<MqlTick>>(); // Времено созданые списки для будующих файлов
                Dictionary<string, List<MqlRates>> rateData = new Dictionary<string, List<MqlRates>>(); // Времено созданые списки для будующих файлов
                List<QuotesDetales> current_fileDetales = new List<QuotesDetales>(); // Времено созданые списки для будующих файлов
                int c = 0;
                int total = smileTickData[key].Count;
                while (c < total)
                {
                    smileData item = smileTickData[key][c];
                    getStrike(item.Price, data.stepStrikes, data.numStrikes, ref strikes);
                    c++;
                    MqlTick tick = new MqlTick
                    {
                        time = item.currentDT,
                        volume = 0
                    };
                    bool addRow = false;
                    for (int j = 0; j < strikes.Count; j++)
                    {
                        double K = strikes[j];
                        for (int i = 0; i < 2; i++)
                        {
                            tick.last = getPrice(item, K, (i == 0 ? true : false));
                            tick.bid = tick.last;
                            tick.ask = tick.last;
                            if (data.spreadBidAsk > 0)
                            {
                                // Делаем еще некоторые действия с преобразованием цены
                            }
                            string currentFile_name = key + "_" + (i == 0 ? "Call" : "Put") + "_" + K.ToString();
                            if (mainWindow.showReadingLine)
                            {
                                if (!cond) cond = true;
                                mainWindow.Invoke(mainWindow.pbUpdater, new object[] { false, max, fileName, (c + 1).ToString() + " х " + total.ToString() + " | " + currentFile_name, false });
                            }
                            else if (cond)
                            {
                                cond = false;
                                mainWindow.Invoke(mainWindow.pbUpdater, new object[] { false, max, fileName, "Создание котировок", false });
                            }
                            addData(tick, currentFile_name, ref tickData, ref rateData, ref addRow, ref DT);
                            QuotesDetales detales_current = new QuotesDetales
                            {
                                assetName = currentFile_name,
                                isCall = (i == 0 ? true : false),
                                strike = K,
                                expiration = smileTickData[key].Max(x => x.currentDT)
                            };
                            if (current_fileDetales.FindAll(x => x.assetName.CompareTo(detales_current.assetName) == 0).Count == 0)
                                current_fileDetales.Add(detales_current);
                        }
                    }
                }
                mainWindow.Invoke(mainWindow.pbUpdater, new object[] { false, max, fileName, "Сохранение данных", false });
                for (int i = 0; i < current_fileDetales.Count; i++)
                {
                    QuotesDetales item = current_fileDetales[i];
                    Writer(pathToFolder + "\\TickData\\" + item.assetName + ".csv", tickData[item.assetName], writeData_tick, "<DATE>\t<TIME>\t<BID>\t<ASK>\t<LAST>\t<VOLUME>");
                    Writer(pathToFolder + "\\CandleData\\" + item.assetName + ".csv", rateData[item.assetName], writeData_rates, "<DATE>\t<TIME>\t<OPEN>\t<HIGH>\t<LOW>\t<CLOSE>\t<TICKVOL>\t<VOL>\t<SPREAD>");
                    Writer(pathToFolder + "\\SmileParamsTickData\\" + key + ".csv", smileTickData[key], writeData_smileParams, "DT Unix miliseconds;Price;S;A;B;C;D;E;T");
                }
                fileDetales.AddRange(current_fileDetales);
                smileTickData.Remove(key);
            }
        }
        return fileDetales;
    }
    private void Writer<T>(string path, List<T> Data, WriteConverter<T> converter, string headdder)
    {
        // пишу в файл
    }
}

Как видно код создания файлов сохранения и прочего не поменялся, я всего лишь поменял подход к формированию информации. Однако скорость снизилась в разы ! от чего так получилось ? буду благодарен если поможете понять данное явление. Понятно что количество проходов по строкам исходного файла возросло в два раза (сначала читаю, сохраняю, затем перечитываю, формирую и сохраняю в файл) однако скорость больше чем в два раза снизилась !

READ ALSO
Выбор изображения из галереи MVVMCross

Выбор изображения из галереи MVVMCross

В axml описана кнопка, по клику на кнопку, нужно открыть галерею и передать в ViewModel путь к выбранному изображениюРеализация в рамках MVVMCross, нужен...

155
WPF и присваивание значения из кода

WPF и присваивание значения из кода

Например есть стиль в XAML:

188
Binding static observablecollection&lt;int&gt;

Binding static observablecollection<int>

Доброго времени суток!

218
Доступ к переопределенным методам

Доступ к переопределенным методам

Есть задача «OverloadResolutionOverride» (Задача):

207