在工做的任務中,須要對客戶端和服務端 通訊包進行落地。把這個作成通用的模塊,在高併發和多線程下,也可以工做。算法
在查閱了大衆化日誌方案後,決定採用:寫日誌和寫文件分離的方式進行。大概內容圖:安全
須要記錄是通訊包,將須要記錄的通訊包推送到隊列,再由一個專門的線程去讀取隊列,將出隊列的數據寫到文件中。這樣將每次直接IO瓶頸,轉化成存儲隊列的大小,瓶頸變成了內存的大小。上代碼:bash
// 掃描隊列,寫文件的線程
private static readonly Thread LogThread;
// 自定義線程安全的Queue
private static readonly ConcurrentQueue<Message> LogQueue;
// 多線程下,操做統一資源的鎖
private static readonly object SyncRoot;
// 在隊列沒有數據時,線程中止掃描標誌
private static readonly AutoResetEvent AutoReset = null;
複製代碼
// 構造函數
static Utils()
{
AutoReset = new AutoResetEvent(false);
SyncRoot = new object();
LogThread = new Thread(WriteLog);
LogQueue = new ConcurrentQueue<Message>();
LogThread.Start();
}
複製代碼
// 記錄日誌
public static void Log(List<Message> msg)
{
foreach (var item in msg)
{
// 隊列入隊
LogQueue.Enqueue(item);
}
// 激活掃描中止的線程(發出信號)
AutoReset.Set();
}
複製代碼
// 寫入日誌
private static void WriteLog()
{
var list = new List<Message>();
while (true)
{
// 若是隊列中有數據
if (LogQueue.Count() > 0)
{
IT2ESBMessage _msg;
// 出隊列
LogQueue.TryDequeue(out _msg);
if (_msg!=null)
{
list.Add(_msg);
}
}
else
{
if (list.Count>0)
{
// 加鎖,在多線程操做的時候,保證安全
lock (SyncRoot)
{
foreach (var item in list)
{
ProcessWriteLog(item);
}
}
ist.Clear();
}
// 在這裏,線程會被暫停,直到收到信號;
AutoReset.WaitOne();
}
}
}
複製代碼
// 寫文件
private static void ProcessWriteLog(Message msg)
{
try
{
FileStream fs;
fs = new FileStream(_fileName, FileMode.Append, FileAccess.Write);
//TODO,進行對文件的寫操做,省略一萬字
}
catch (Exception ex)
{
Debug.WriteLine(string.Format("寫入日誌失敗,緣由:{0}", ex.Message));
}
}
複製代碼
AutoResetEvent 關鍵字多線程
Reset ():將事件狀態設置爲非終止狀態,致使線程阻止;併發
Set ():發送信號到等待線程以繼續其工做;函數
有點相似於計算機中的信號量,回顧《操做系統》中的信號量吧,什麼銀行家算法,什麼信號量已經忘得一乾二淨了。高併發
信號量 用在多線程多任務同步的,一個線程完成了某一個動做就經過信號量告訴別的線程,別的線程再進行某些動做。ui
互斥鎖 是用在多線程多任務互斥的,一個線程佔用了某一個資源,那麼別的線程就沒法訪問,直到這個線程unlock,其餘的線程纔開始能夠利用這個資源spa