Возможная утечка памяти в простой функции обработки пакетного файла в c# - PullRequest
1 голос
/ 19 июня 2020

Я запускаю очень простую функцию, которая читает строки из текстового файла партиями. Каждая строка содержит запрос sql, поэтому функция захватывает указанное количество запросов, выполняет их в базе данных SQL, а затем захватывает следующий пакет запросов, пока не будет прочитан весь файл. Проблема в том, что со временем с очень большими файлами процесс начинает значительно замедляться. Я предполагаю, что где-то в функции есть утечка памяти, но не могу определить, где она может быть. Пока эта функция работает, больше ничего не происходит. Мои навыки программирования в лучшем случае грубые, так что, пожалуйста, go полегче со мной. :)

    for (int x = 0; x<= totalBatchesInt; x++)
    {
    var lines = System.IO.File.ReadLines(file).Skip(skipCount).Take(batchSize).ToArray();
    string test = string.Join("\n", lines);
    SqlCommand cmd = new SqlCommand(test.ToString());
        try
        {
            var rowsEffected = qm.ExecuteNonQuery(CommandType.Text, cmd.CommandText, 6000, true);
            totalRowsEffected = totalRowsEffected + rowsEffected;
            globalRecordCounter = globalRecordCounter + rowsEffected;
            fileRecordCounter = fileRecordCounter + rowsEffected;
            skipCount = skipCount + batchSize;
            TraceSource.TraceEvent(TraceEventType.Information, (int)ProcessEvents.Starting, "Rows 
            progress for " + folderName + "_" + fileName + " : " + fileRecordCounter.ToString() + " 
            of " + linesCount + " records");
        }
        catch (Exception esql)
        {           
            TraceSource.TraceEvent(TraceEventType.Information, (int)ProcessEvents.Cancelling, "Error 
            processing file " + folderName + "_" + fileName + " : " + esql.Message.ToString() + ". 
            Aborting file read");       
        }
    }

1 Ответ

3 голосов
/ 19 июня 2020

В вашем коде много ошибок:

  1. Вы никогда не избавляетесь от своей команды. Это собственный дескриптор драйвера ODB C, ждать, пока сборщик мусора не удалит его, - очень плохая практика.

  2. Вы все равно не должны отправлять эти команды по отдельности. Либо отправьте их все сразу в одной команде, либо используйте транзакции, чтобы сгруппировать их вместе.

  3. Это причина, по которой со временем он становится медленнее: File.ReadLines(file).Skip(skipCount).Take(batchSize) будет читать один и тот же файл снова и снова и игнорировать растущее количество строк с каждой попыткой, и поэтому он растет все медленнее и медленнее по мере того, как количество игнорируемых (но обрабатываемых) строк становится все больше и больше.

Исправить # 3 , просто создайте перечислитель один раз и повторяйте его партиями. В чистом C# вы можете сделать что-то вроде:

using var enumerator = File.ReadLines(file).GetEnumerator();

for (int x = 0; x<= totalBatchesInt; x++)
{
    var lines = new List<string>();
    while(enumerator.MoveNext() && lines.Count < batchSize)
        list.Add(enumerator.Current);
    string test = string.Join("\n", lines);
    // your code...
}

Или, если вы используете Morelinq (что я рекомендую), что-то вроде этого:

foreach(var lines in File.ReadLines(file).Batch(batchSize))
{
    // your code...
}
...