C#高速数据记录数据处理

时间:2009-08-26 17:33:58

标签: c# caching

我编写了一个应用程序,通过UDP记录来自嵌入式系统的跟踪数据。目前,我收到数据报并解析出可变长度记录并将它们存储在列表中。前端可以访问列表并显示数据(图形和文本列表等)。

我遇到的问题是有时我需要记录大量的数据。我的列表实现导致了内存不足异常。

我的要求是:

  • 允许多线程读取和写入数据(不能只发布过程)
  • 处理大量数据(最差情况下~2MB / s ... 7.2GB /小时的日志记录)
  • 允许存储数据集
  • 随机阅读,基于索引,访问

有没有人对如何攻击这个提出一些建议?以下是我的一些想法:

  • 我想要一个漂亮的磁盘备份,内存缓存List。看起来好像存在,但我还没找到。
  • 本地数据库?我对数据库知之甚少,但看起来有些过分。
  • 立即将数据存储到文件中。在内存中保留一个列表,其中包含每个记录索引的字节偏移量。我的读者可以同时访问吗?

4 个答案:

答案 0 :(得分:1)

本地数据库确实是处理这种情况的好方法 - 特别是因为查询可以帮助您调查日志。另外,你的UDP接收程序可能只是一个单独的线程,它会在数据库中发送信息(如果你的数据真的快节奏,你可以有两个缓冲区并在它们之间交替;将完整的缓冲区刷新到数据库,而另一个是填满)。这实际上取决于你的项目规模。

您可以随时使用第三个选项(立即存储到文件中),并使用单独的“日志调查”工具来读取该文件而不会遇到OOM异常。

答案 1 :(得分:0)

.NET 4具有无锁队列。您可以设置一个队列,其中一个线程将UDP组件中的内容添加到日志中,另一个线程正在使用这些日志并将它们放入文件或数据库中。

答案 2 :(得分:0)

我所拥有的是一个队列,我添加了我正在使用Log(字符串内容)方法登录的消息。我有另一种方法,我在后台线程中开始,它不断读取队列并写入文件。即使在数据过多的情况下可以完成写入,也会保留时间戳。

日志记录方法是静态的和公共的,因此可以从任何线程调用它。我不能保证这个代码编译,因为我把它从我的项目中删除并删除了一些东西。

我发现由于我的计算机DISK I / O很糟糕,我没有收到超过1或2个线程写入的性能提升。如果将日志记录拆分为多个文件,可能会加快速度,但不能肯定地说。

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();

答案 3 :(得分:0)

我正在使用Josiah的方法来创建可重用的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并不总是更改。