0

I have a DataTable with multiple TimeStamp (DateTime) columns per row. I want to create a timeout value so when the TimeStamp passes DateTime.Now-timeoutValue, it will be nulled. And when all TimeStamp values are nulled, the row is deleted.

It's currently implemented with timers and loops. It's starting to get very laggy with many entries, is there a more automated efficient way? Expressions or something? Here are snips of my code:

public ReadsList(object _readers)
{
    _readers = List of things that add to datatable
    dataTable = new DataTable();
    Timeout = 5;

    aTimer = new System.Timers.Timer(5000);
    aTimer.Elapsed += new ElapsedEventHandler(UpdateReads);
    aTimer.Enabled = true;
}

public void Add(object add)
{
    //Checks if object exists, update TimeStamp if so, else, add new row
}

private void UpdateReads(object source, ElapsedEventArgs e)
{
    //Clean DataTable
    foreach (DataRow row in dataTable.Rows.Cast<DataRow>().ToList())
    {
         int p = 0;
         foreach (var i in _readers)
         {
             p += i.Value;

             for (int b = 1; b <= i.Value; b++)
             {
                 if (row[(i.Key + ":" + b)] != DBNull.Value)
                 {
                     if (Timeout == 0)
                         Timeout = 99999;
                     if (DateTime.Parse(row[(i.Key + ":" + b)].ToString()) <
                         DateTime.UtcNow.AddSeconds(-1*Timeout))
                     {
                         row[(i.Key + ":" + b)] = DBNull.Value;
                     }    
                 }
                 else
                 {
                       p -= 1;
                 }
             }

        }
             //Remove Row if empty
             if (p == 0)
             {
                row.Delete();
                //readCount -= 1;
             }
        }
     dataTable.AcceptChanges();
     OnChanged(EventArgs.Empty);
}
4

2 回答 2

1

Here are a couple of ideas for minor improvements which may add up to a significant improvement:

  1. You're building the column key (i.Key + ":" + b) more than once. Build it once within your inner foreach and stick it in a variable.
  2. You are reading the column (row[(i.Key + ":" + b)]) more than once. Read it once and stick it in a variable so that you can use it multiple times without having to incur the hash table lookup each time.
  3. You are adjusting the timeout (if (Timeout == 0) Timeout = 99999;) more than once. Adjust it once at the beginning of the method.
  4. You are calculating the timeout DateTime (DateTime.UtcNow.AddSeconds(-1*Timeout)) more than once. Calculating it once at the beginning of the method.
  5. You are always looking up column values by string. If you can store the column ordinals somewhere and use those instead, you'll get better performance. Just make sure you look up the column ordinals once at the beginning of the method, not inside either of the foreaches.
  6. You are parsing strings into DateTimes. If you can store DateTimes in the DataTable, you wouldn't have to parse each time.
于 2013-06-05T22:09:09.797 回答
0

First off, there are a few things you can do here to increase the speed. First off, datatables are meant to pull data from a database, and are not really high end collections. In general, Generic Lists are 4x faster than Datatables, and use significantly less memory. Also, your biggest time cost is coming from the DateTime.Parse right in the middle of your third loop, and performing the DateTime calculation right in the middle of the loop for your expiration time. It doesnt appear the expiration time is based upon the records original value, so you should definitely generate that once before the loop starts.

I would recommend creating a data type for your record format, which would allow you to store the records dates as DateTime Objects, basically consuming the conversion time when you first intialize the list, rather than doing the tryparse everytime through. So using a List to store the data, then you could simply do something like :

var cutOffTime = DateTime.UtcNow.AddSeconds(-99999); // Do this to save creating it a billion times.
var totalRecords = AllRecords.Count; // Do this so the value is not re-evaluated

for(var i=0;i<totalRecords;i++)
{
   var rec = AllRecords[i];

   if(rec.TimeThingy1 < CutOffTime && rec.TimeThingy2 < cutOffTime && rec.TimeThingy3 < cutOffTime)    
    {
      AllRecords.RemoveAt(i); // You could even add this to another list, and remove all at the end, as removing an object from a list during mid-iteration is costly
    } 
}
于 2013-06-05T22:07:08.337 回答