我正在尝试编写一个异步日志记录类,但无法决定何时将日志写入文件。
现在,我正在考虑将所有日志存储在一个向量中,然后按它们的时间戳对它们进行排序。
问题是我应该什么时候将日志写入文件?如果我在写入磁盘之前等待 N 条日志,我可能会错过一个日志条目,或者如果我们已经达到向量中的 N 条日志,则一个日志条目可能会被乱序写入日志。
我在考虑也许使用某种计时器,但我不确定这是否会更好。
我将不胜感激任何想法,谢谢。
我正在尝试编写一个异步日志记录类,但无法决定何时将日志写入文件。
现在,我正在考虑将所有日志存储在一个向量中,然后按它们的时间戳对它们进行排序。
问题是我应该什么时候将日志写入文件?如果我在写入磁盘之前等待 N 条日志,我可能会错过一个日志条目,或者如果我们已经达到向量中的 N 条日志,则一个日志条目可能会被乱序写入日志。
我在考虑也许使用某种计时器,但我不确定这是否会更好。
我将不胜感激任何想法,谢谢。
如果您正在处理异步日志记录,我建议使用线程安全队列将所有带有时间戳的消息泵送到日志记录线程工作者。然后,日志工作者可以处理出现在队列中的块中的所有消息。
这种线程安全的队列抽象允许您设置缓冲区大小或使其不受限制(如果队列/缓冲区通过条件变量填满,您可以向线程发送消息),同时从多个线程记录日志,并且即使在发生错误后处理日志,如果您将主线程包装在一个 try catch 循环中,该循环等待记录器在退出之前完成(好吧,它不会帮助解决段错误,但它仍然有助于解决大多数错误)。此外,您可以将消息发送到记录器并在主程序线程中继续前进,而无需等待任何 IO 操作(可能会大大节省执行时间)。实施起来也不难。队列的 API 非常有限,因此您与数据结构的交互只能用一些范围锁定来包装一个列表。
您为此实施付出了很小的代价——即锁定价格。但是,如果您需要添加任何其他多线程,则不必重新构建记录器,并且通过将 IO 卸载到另一个线程,您可能会比单线程记录器更快。
如果您有消息乱序,您有两种选择。在队列的日志工作者端进行日志排序(为工作者保留一个本地缓冲区以保留较旧的消息)。或者将日志队列的实现更改为优先级队列,使用时间戳对消息进行排序并在插入时支付更高的价格。后者可能更容易实现,但要付出更高的同步代价。
我已经在 C++ 中使用 Boost 线程使用了这种策略,并且效果很好。我可以崩溃并且仍然从崩溃之前获取日志,并且当我将工作分支到各个线程以轻松进行可并行化的工作时,我只是在任何地方使用相同的日志抽象来轻松跟踪事件顺序。
我同意关于在没有缓冲(或显式刷新)的情况下乱序写入它们的评论。但是,如果您想按顺序编写它们,我将有一个单独的线程来管理编写。您将定义一个特定的延迟量(大概以秒为单位),您可以合理地保证将涵盖任何迟到的情况。
所以在一个非常基本的意义上,你会有一个线程函数,比如:
time_t writeDelay = 10; // 10 seconds
for(;;)
{
// Sleep for a second
//[OS-specific code here]
time_t now;
time(&now);
WriteLogEntriesUpTo(now - writeDelay);
}
这里的问题是,如果你做得不对,将你的日志条目分类到一个向量中可能会给你的记录器带来很多开销。至少使用 adeque
这样您就可以轻松地从前面弹出条目。如果我要这样做,我可能会为我的日志字符串和队列中的简单记录设置一个大缓冲区(实际上是一个内存池)。带有时间戳和指针的东西会使排序变得容易。
struct LogEntry {
time_t timestamp;
char *message;
};
而不是把这些放在一个deque
我会实现某种有序列表(同样,内存池)。让这一切快速完成将是相当繁琐的。你想得越多,乱写就越有意义。