選項2聽起來最好。選項1肯定會創建太多後臺線程,而選項3聽起來比它需要的更復雜。
你可能會嘗試這樣的事情。
鑑於這種類:
class LogEntry
{
public string IpAddress { get; set; }
public string UserAgent { get; set; }
public DateTime TimeStamp { get; set; }
public string Url { get; set; }
//whatever else you need
}
使用這個類來進行日誌記錄:
class SiteLogger
{
private static object loggerLock = new object();
private static List<LogEntry> _pendingEntries = new List<LogEntry>();
private static Thread savingThread;
public static void AddEntry(LogEntry entry)
{
// lock when accessing the list to avoid threading issues
lock (loggerLock)
{
_pendingEntries.Add(entry);
}
if (savingThread == null)
{
// this should only happen with the first entry
savingThread = new Thread(SaveEntries);
savingThread.Start();
}
}
private static void SaveEntries()
{
while (true)
{
while (_pendingEntries.Count > 0)
{
// lock around each individual save, not the whole loop
// so we don't force one web request to wait for
// all pending entries to be saved.
lock (loggerLock)
{
// save an entry to the database, however the app does that
MyDatabase.SaveLogEntry(_pendingEntries[0]);
_pendingEntries.RemoveAt(0);
}
}
Thread.Sleep(TimeSpan.FromSeconds(2));
// 2 seconds is a bit of an arbitrary value. Depending on traffic levels,
// it might need to go up or down.
}
}
}
我跑這與沒有任何數據庫參與一個簡單的命令行測試程序(模擬由數據庫調用睡10 ms),它似乎很好,但在進入生產環境之前顯然應該進行更多的測試。而且,如果請求的速度比將數據保存到數據庫的速度要快(這不太可能,但應該考慮),那麼當然會出現問題。
更新,2018年2月:現在這個來看,我知道你可能有兩個savingThread
情況下,如果你用螺紋時機倒黴(你應該假設你會)結束。和new Thread()
是現在在C#中做這種事情的老方法。我將把這個作爲練習的現代,更線程安全的實現留給讀者。