Ограничить использование ЦП процессом

У меня есть служба, которая периодически проверяет папку для файла и затем обрабатывает ее. (Читает, извлекает данные, сохраняет их в sql)

Итак, я запустил его на тестовом поле, и потребовалось немного больше времени, чем ожидалось. Файл имел 1,6 миллиона строк, и он продолжал работать через 6 часов (затем я пошел домой).

Проблема в том, что ящик, на котором он работает, теперь абсолютно искалечен - удаленный рабочий стол выходил из строя, поэтому я даже не могу его остановить, чтобы остановить процесс, или приложить отладчик, чтобы увидеть, как далеко продвигается и т.д. Он прочно использует 90% + процессор, и все другие запущенные сервисы или приложения страдают.

Код (из памяти не может компилироваться):

List<ItemDTO> items = new List<ItemDTO>();
using (StreamReader sr = fileInfo.OpenText())
{
    while (!sr.EndOfFile)
    {
        string line = sr.ReadLine()
        try {
           string s = line.Substring(0,8);
           double y = Double.Parse(line.Substring(8,7));

           //If the item isnt already in the collection, add it.
           if (items.Find(delegate(ItemDTO i) { return (i.Item == s); }) == null)
               items.Add(new ItemDTO(s,y));
         }
         catch { /*Crash*/ }
    }
    return items;
}

- Поэтому я работаю над улучшением кода (любые подсказки оценены).

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

Так что я хочу от вас прекрасных людей: 1) Является ли мой код ужасно не оптимизированным? 2) Могу ли я ограничить объем процессора, который может использовать мой кодовый блок?

Приветствует всех

Ответ 1

  • Выполнение поиска в списке - это операция O (n), это означает, что по мере того, как список становится длиннее, для поиска элементов требуется больше времени. Вы можете рассмотреть возможность размещения элементов в HashSet в .NET 4.0/3.5 или использовать Словарь для более ранних версий .NET, который может действовать как индекс, если вам нужны элементы в списке, чтобы сохранить исходный порядок, который вы можете продолжать помещать в список, но используйте HashSet/Словарь для проверки.

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

Ответ 2

Вместо того, чтобы ограничивать использование ЦП, вам, вероятно, будет лучше отключить его приоритет, поэтому он будет работать только тогда, когда ничего не остается делать. Другие уже упоминали о возможностях оптимизации, поэтому я не буду пытаться попасть в эту часть.

Ответ 3

Найти в списке O (n). Если файл имеет 1,6 миллиона строк (т.е. 1,6 миллиона элементов), вы будете многократно перебирать список из 1 миллиона экземпляров, что будет тратить много времени.

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

При использовании .NET 3.5 вы можете использовать коллекцию HashSet, которая дает вам амортизированный O (1) для поиска. Коллекция словарей использует .NET 2.0

Затем вы должны спросить себя, если файл имеет 1,6 миллиона строк, у вас достаточно памяти? Если да, то анализ файла в памяти будет быстрее, чем отправка его в базу данных для обработки дубликатов, но если у вас недостаточно памяти, вы будете пейджинговым. Много. (что, вероятно, происходит сейчас).

Ответ 4

Как говорили другие, исправьте структуру данных.

Теперь мои глаза ударили по этой фразе "периодически проверяет папку для файла, а затем обрабатывает ее". Как часто "периодически" и зачем обрабатывать файл, который, вероятно, не изменился?

Вы можете взглянуть на System.IO.FileSystemWatcher http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx

Ответ 5

Не можете ли вы загрузить этот файл с SqlBulkCopy Class, а затем выполнить обработку на сервере базы данных?

Ответ 6

В ответ на 1) я бы использовал отсортированный список (если есть много избыточных данных) или хеш-словарь вместо обычного, чтобы ускорить поиск.

Вот другое сообщение, которое поможет вам решить между двумя подходами.

для вопроса 2), я бы установил приоритет потока ниже обычного. См. здесь.

Ответ 7

Вам действительно нужно хранить все данные в памяти? Вы можете сохранить его в базе данных (если вам нужно что-то простое и мощное использование Sqlite) и обрабатывать его с помощью sql.

Ответ 8

  • HashSet
  • Threading с более низким приоритетом
  • Какой-то SQL-массив вставки

Ответ 9

Я не программист на С#, но, глядя на логику, я думаю,

  • Вы создаете новый строковый объект каждый раз в цикле. Если я должен сделать это в java, вместо использования строкового объекта я бы использовал StringBuffer.

  • Ваш файл данных большой, поэтому я думаю, что у вас должна быть логика для очистки информации в базы данных после каждого "n" количества записей. Вам потребуется дополнительная логика для записи записи очищаются до сих пор. В качестве альтернативы, поскольку ваша логика захватывает только первую строку данных & Амп; игнорирует последующие дубликаты, вместо использования метода поиска, вы не можете просто попытаться вставить данные и захват сбой sql.

  • Логика обработки должна быть в отдельном потоке, чтобы поддерживать реакцию системы.