用隊列解決高併發 之 記錄日誌
用隊列解決高併發 之 記錄日誌
在高併發量的情況下,有多種平時不會出現的問題會導致用戶等待,下面我們用日誌記錄爲例來說明一種解決方案——隊列。
創建一個工具類:LogCommon 如下:
namespace Heima8Web.Common
{
public class LogCommon
{
public static Queue<string> LogQueue = new Queue<string>(); //實例化一個隊列
static LogCommon() //日誌寫入文件的方法在類的靜態構造函數中實現,這樣,在隊列被調用的時候,會自動調用此方法
{
string strFileName = HttpContext.Current.Request.MapPath("/App_Data/Log/" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt"); //在新開啓的線程以外獲取文件路徑(每一個請求對應一個線程,到新的線程裏去以後,就不能獲得到當前上下文了)
//開啓線程池來寫日誌
ThreadPool.QueueUserWorkItem(a =>
{
while (true)
{
string ex = string.Empty;
lock ("Itcast-DotNet-AspNet-Glable-LogLock")
{
if (LogQueue.Count > 0) //如果隊列中有數據,將其出隊列
{
ex = LogQueue.Dequeue();
}
else
{
Thread.Sleep(30); //如果沒有數據,讓線程睡30毫秒,之後進入下一輪循環
continue;
}
}
//創建流,將日誌寫入到文件中
using (FileStream fs = new FileStream(strFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (StreamWriter writer = new StreamWriter(fs,Encoding.Default))
{
writer.Write(ex.ToString());
}
}
}
});
}
public static void WriteLog(string str) //將日誌寫入到隊列中的方法
{
lock ("Itcast-DotNet-AspNet-Glable-LogLock")
{
LogQueue.Enqueue(str);
}
}
}
}
------------
在 HttpApplication 管道的 Application_Error中註冊事件,
即在 global 文件的 Application_Error事件中寫如下代碼:
protected void Application_Error(Object sender, EventArgs e)
{
Exception ex = Server.GetLastError(); //拿到錯誤消息
Common.LogCommon.WriteLog(ex.ToString()); //將錯誤消息加到隊列裏面去
}
=========================================================
注:在調用 Common.LogCommon.WriteLog 方法的時候,靜態構造函數LogCommon()會被自動調用,因爲
C#在使用靜態構造函數時的幾個原則:
1.靜態構造函數在創建類的實例之前會被調用,因此在所有實例構造函數之前會被調用。
2.靜態構造函數在創建類的第一個實例之前會被調用。
3.靜態構造函數在引用靜態字段之前會被調用。
在新開啓的線程裏面是獲取不到當前上下文的