C # высокая скорость обработки данных регистрации данных - PullRequest
3 голосов
/ 26 августа 2009

Я написал приложение, которое регистрирует данные трассировки из встроенной системы через UDP. В настоящее время я получаю дейтаграммы, анализирую записи переменной длины и сохраняю их в виде списка. Внешний интерфейс может получить доступ к списку и представить данные (графики и текстовые списки и т. Д.).

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

Мои требования:

  • Разрешить многопоточное чтение и запись данных (нельзя просто постобработать)
  • Обработка больших объемов данных (в худшем случае ~ 2 МБ / с ... 7,2 ГБ / час ведения журнала)
  • Разрешить хранение набора данных
  • Случайное чтение, на основе индекса, доступ

У кого-нибудь есть предложения о том, как на это напасть? Вот несколько мыслей, которые у меня были:

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

Ответы [ 4 ]

1 голос
/ 26 августа 2009

Локальная база данных действительно была бы хорошим способом справиться с этим - особенно потому, что запросы помогли бы в вашем исследовании журналов. Кроме того, тогда ваша принимающая UDP-программа может быть просто отдельным потоком, который выплевывает информацию в базу данных (если ваши данные ДЕЙСТВИТЕЛЬНО быстро меняются, вы можете иметь два буфера и чередоваться между ними; сбросить полный буфер в базу данных, пока другой заполнение). Это действительно зависит от масштаба вашего проекта.

Вы всегда можете использовать свой третий вариант (сохранение в файл сразу) и иметь отдельный инструмент «Log Investigation», который читает этот файл, не сталкиваясь с исключениями OOM.

0 голосов
/ 14 декабря 2009

Я использую подход Иосии для создания многоразового класса Logger. Тем не менее, я использую флаг вместо while (true), который позволяет завершить цикл при значении false.

while (logging)  // instead of while(true)
{
    while (logQueue.Count > 0)
    {
        string s = "";
        lock (logLock)
        {
           s = logQueue.Dequeue();
        }
        write(s);
    }
    Thread.Sleep(timer);
}

Это работает хорошо, но я обнаружил, что можно ставить в очередь тысячи сообщений до того, как значение logQueue.Count действительно изменится.

for (int i = 0; i <5000; i++)
{
     lock (logLock)
     {
       logQueue.Enqueue(i.toString());
     }
}
logging = false;

Иногда приведенный выше код приводит к тому, что LogLoop завершается до того, как в файл будут записаны какие-либо сообщения. Установка паузы перед установкой логирования на false исправляет это, но я все еще удивлен, что logQueue.Count не всегда изменяется, прежде чем очередь распознает сообщения.

0 голосов
/ 26 августа 2009

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

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

Я обнаружил, что я не получаю повышения производительности при записи более 1 или 2 потоков, потому что мой компьютер DISK I / O Sucks. Возможно, вам удастся ускорить это, если вы разбили свою запись на несколько файлов, хотя точно сказать не могу.

private static StreamWriter sw;
private static Queue<string> logQueue = new Queue<string>();
public static string logLock = "";
public static void LogLoop()
{
    sw = new StreamWriter("logFilePath.log"), true);
    sw.AutoFlush = true;
    while (true)
    {
        while (logQueue.Count > 0)
        {
            string s = "";
            lock (logLock) // get a lock on the queue
            {
                s = logQueue.Dequeue();
            }
            sw.WriteLine(s);                
        }
        Thread.Sleep(10);
    }
}
public static void Log(string contents)
{
    contents = DateTime.Now.ToString("MM-dd-yy - HH:mm:ss ffff") + " - " + contents; // add a timestamp

    lock (logLock) // get a lock on the queue
    {
        logQueue.Enqueue(contents);
    }
}

Так я запускаю метод фонового потока.

Thread logThread = new Thread(LogLoop);
logThread.IsBackground = true;
logThread.Name = "Logging Thread";
logThread.Start();
0 голосов
/ 26 августа 2009

.NET 4 имеет блокировку свободных очередей. Вы можете настроить очередь, в которой один поток добавляет данные из компонента UDP в журнал, а другой поток использует эти журналы и помещает их в файл или базу данных.

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