选项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#中做这种事情的老方法。我将把这个作为练习的现代,更线程安全的实现留给读者。