2011-10-19 149 views
1

我使用VS 2005傳遞進行日誌記錄有效

我有大約10-12個不同類型的如雙,INT,弦長和布爾變量,我要登錄另一個線程之間大量的變量最小線程。高架。

當前,每當我必須登錄時,我「新建」一個數組列表,在其中添加所有變量,然後將其作爲參數傳遞給LoggerClass.Log()。在LoggerClass中,它設置/重置事件,另一個線程讀取arraylist的值。

由於該函數被調用了很多,執行「new」效率不是很高,我正在尋找一種方法將所有值傳遞給另一個線程,而無需動態內存分配。

我腦海中的另一個替代方案是不是「新」的數組列表,但只是不斷增加它,但問題在於數組列表的大小可能變得令人en目。

有什麼建議嗎?

繼承人的代碼

//This function gets called a thousand times per second 

private void MyLogic(MyClass LogObj) 
{ 

    ArrayList MyArrList = new ArrayList(15);//This line causes periodic performance outliers 
          MyArrList.Add("Q"); 
          MyArrList.Add(LogObj.valString); 
          MyArrList.Add(LogObj.ValDouble); 
          MyArrList.Add(LogObj.ValInt); 
          MyArrList.Add(LogObj.valString2); 
          MyArrList.Add(LogObj.ValDouble2); 
          MyArrList.Add(LogObj.ValInt2); 
          MyArrList.Add(LogObj.valString3); 
          MyArrList.Add(LogObj.ValDouble3); 
          MyArrList.Add(LogObj.ValInt3); 
          MyArrList.Add(LogObj.valString4); 
          MyArrList.Add(LogObj.ValDouble4); 
          MyArrList.Add(LogObj.ValInt4); 

    MyLogger.Log(MyArrList); 
} 


Class MyLogger 
{ 
    private Queue   m_logQueue; 

    public void Log(ArrayList LogArr) 
    { 
    lock (m_LogQueue) 
    { 
     m_LogQueue.Enqueue(LogArr); 
    } 

    m_Event.Set(); 
    } 
} 

private void LogThread() 
{   
    ArrayList ValuesToLog = new ArrayList(); 
    StringBuilder StringBuf = new StringBuilder(); 
    string csFileName = "MyLog"; 

    using (StreamWriter sw = new StreamWriter(new FileStream(csFileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))) 
    { 
    while (m_bRun) 
    { 
     m_Event.WaitOne(); 
     try 
     { 
     while (true) 
     { 
      lock (m_logQueue) 
      { 
      if (m_logQueue.Count > 0) 
      { 
       ValuesToLog = (ArrayList)m_logQueue.Dequeue();          
      } 
      else 
       break; 
      } 

      StringBuf = new StringBuilder(); 
      StringBuf.Append(DateTime.Now); 
      StringBuf.Append(","); 

      for (int i = 0; i < (ValuesToLog.Count - 1); i++) 
      { 
      StringBuf.Append(","); 
      StringBuf.Append(ValuesToLog[i]); 
      } 

      sw.WriteLine(StringBuf.ToString()); 

      if (m_bAbort) break; 
      if (m_EventStop.WaitOne(0, true)) 
      break; 
     } 
     sw.Flush(); 
     } 
     catch(Exception e) 
     { 

     } 
    } 
    } 
} 
+1

你爲什麼不使用'List '? ArrayLists是.net 1.1。 –

+0

@AustinSalonen:他傳球不同。 – SLaks

+0

'列表'然後呢? –

回答

0

如果你真的確定問題每次分配新的列表,你可以回收。

收集未使用的列表,該列表開始爲空。當集合中有一個列表時,取出它(並將其從集合中刪除)。否則,請創建一個新的。當您完成日誌記錄時,Clear()列表並將其返回給集合。

當然,您從多個線程訪問集合,因此您必須確保以線程安全的方式訪問它。

+0

說我在啓動時實例化1000 ARrayList並將它們添加到隊列中。 MyLogic()可以從集合中獲取一個數組列表並使用它。 MyLogger.LogThread()然後可以從arraylist中記錄值並在其上調用clear()?我的問題是,MyLogic()如何知道要獲取哪個arrayList?我認爲索引將是一個自動增量數,一旦達到1000,它就開始從索引1的隊列中獲取數組列表。 – bsobaid

+0

一個'Dequeue()'返回。而且,您不必擔心'Queue'(或更好的'Queue ')如何管理其索引,它會正確執行。但是您必須指出收集中沒有未使用的列表的情況。 – svick

+0

我明白了。所以你的意思是在啓動時,我排入了1000個陣列列表。然後MyLogic()調用MyQueue.Dequeue函數來獲取一個數組列表併爲其添加值,並將該數組列表傳遞給loggerthread。然後Loggerthread可以清除()它從MyLogic()獲得的數組列表。想知道,當我說Queue.Dequeue時,Queue會重新使用之前使用過的數組列表,然後再清除嗎?或者隊列會動態地繼續增加其大小而不重複使用先前清除的數組列表? – bsobaid

0

我還沒有做過任何測量,我不一定同意你的結論或你對這種測井類型的方法,但我不會讓這阻止我提出建議......

//Use this to hold the information that you want to log. 
public class LogRecord 
{ 
    private IEnumerable<object> values; 

    public LogRecord(params object [] data) 
    { 
    LogTime = DateTime.Now; 
    values = data; 
    } 

    public DateTime LogTime { get; set; } 
    public IEnumerable<object> Values 
    { 
    get 
    { 
     yield return LogTime; 
     foreach(var v in values) yield return v; 
    } 
    } 
} 

// 
private void MyLogic(MyClass LogObj) 
{ 
    var record = new LogRecord("Q", LogObj.Var1, LogObj.Var2, LogObj.Var3); 
    MyLogger.Log(record); 
} 

class MyLogger 
{ 
    public void Log(LogRecord record) 
    { 
    //Do a bunch of threading stuff... 

    string msg = string.Join(",", record.Values); 

    //Write the message to the stream 
    } 
} 

那裏還有一個new,但是這種方法(爲每個日誌語句創建一個新的日誌記錄)被其他流行的日誌框架(如log4net,NLog和EnterpriseLibrary)使用。據我所知,在這些框架中你沒有聽到很多關於性能的抱怨。

我不知道這是比你有什麼更好或更差。另外,我不知道它是否解決了您所說的您看到的性能問題。另一方面,它確實簡化了代碼,無論是創建日誌消息還是將它組合成字符串以寫入流。

如果您非常關心性能,並且您的信息每秒記錄一千次,那麼您可以查看NLog的CurrentTimeGetter實現。它的目的是優化時間檢索,因爲時間通常不會從一個記錄的消息改變到下一個。您可以在此鏈接找到它:

https://github.com/jkowalski/NLog/blob/master/src/NLog/Internal/CurrentTimeGetter.cs

我的最終建議很可能會嘗試使用像log4net的或NLOG現有的日誌框架。現在我個人會建議首先給NLog一個嘗試,因爲它剛剛有一個重要的新版本。

+0

我在代碼中添加了另一個新的代碼,我可以將其刪除,並且大多數性能異常值都消失了。 – bsobaid

0

DateTime.Now.ToString()可能是一個問題。也許考慮使用別的東西?這給了我很大的性能提升 -

char[] buffer = new char[21]; 

static string DateTimeNowToString()  
{ 

    var now = DateTime.Now; 
    buffer[2] = buffer[5] = '.';   
    buffer[8] = ' ';   
    buffer[11] = buffer[14] = buffer[17] = ':';   
    Write2(buffer, now.Month, 0);   
    Write2(buffer, now.Day, 3);   
    Write2(buffer, now.Year % 100, 6);   
    Write2(buffer, now.Hour, 9);   
    Write2(buffer, now.Minute, 12);   
    Write2(buffer, now.Second, 15);   
    Write3(buffer, now.Millisecond, 18); 

    return new String(buffer) 
}  

static void Write2(char[] buffer, int value, int offset)  
{   
    buffer[offset++] = (char)('0' + (value/10));   
    buffer[offset] = (char)('0' + (value % 10));  
} 

static void Write3(char[] buffer, int value, int offset)  
{   
    buffer[offset++] = (char)('0' + (value/100));   
    buffer[offset++] = (char)('0' + ((value/10) % 10));   
    buffer[offset] = (char)('0' + (value % 10));  
} 
+0

這是真的,DateTime.Now是壞的,但我在loggerthread上做,所以不應該影響我的正常處理。 – bsobaid