在 StreamSink
类中,成员变量 _write_occurred
的作用是 跟踪自上次刷新(Flush)以来是否有写入操作发生 ,其核心目的是 优化 I/O 性能。以下是详细解析:
_write_occurred
的作用
1. 避免不必要的刷新(Flush)
- 机制 :
当write_log
方法(日志写入)被调用时,_write_occurred
会被设为true
;
当flush_sink
方法(主动刷新)被调用时,仅在_write_occurred
为true
时执行实际的fflush
操作,随后将其重置为false
。 - 优化意义 :
避免在无新日志写入时频繁调用fflush
(系统调用),减少 I/O 开销。
2. 状态跟踪
- 写入标记 :
记录自上次刷新后是否有新数据写入缓冲区。若未写入,跳过刷新操作。 - 示例场景 :
若连续多次调用flush_sink
但无新日志写入,只有第一次会真正执行fflush
。
代码流程解析
写入日志时
cpp
void write_log(..., std::string_view log_statement) override {
// ... 写入日志到文件
safe_fwrite(...); // 实际写入操作
_write_occurred = true; // 标记有写入发生
}
- 写入后必标记 :无论日志内容是否为空,只要调用
write_log
即标记为true
。
主动刷新时
cpp
void flush_sink() override {
if (!_write_occurred || !_file) {
return; // 无写入或文件未打开时直接返回
}
flush(); // 执行实际刷新
}
void flush() {
_write_occurred = false; // 重置标记
fflush(_file); // 系统调用刷新缓冲区
}
- 条件刷新 :仅在确实有写入时调用
fflush
,避免无意义刷新。
设计必要性
性能优化
场景 | 无 _write_occurred |
有 _write_occurred |
---|---|---|
高频写入 | 每次 flush 触发 fflush ,I/O 压力大 |
仅在必要时触发 fflush ,减少系统调用 |
低频写入 | 多余的 fflush 浪费 CPU 周期 |
无写入时跳过 fflush ,节省资源 |
资源保护
- 文件句柄有效性 :
若文件被意外关闭(如_file
变为nullptr
),flush_sink
会直接返回,避免操作无效指针。
典型应用场景
1. 日志批量写入
cpp
// 连续写入多条日志
sink.write_log(...); // _write_occurred = true
sink.write_log(...); // _write_occurred = true
sink.flush_sink(); // 实际刷新,重置 _write_occurred = false
sink.flush_sink(); // 直接返回(无新写入)
2. 定时刷新策略
cpp
// 定时器每 1 秒触发刷新
void on_timer() {
sink.flush_sink(); // 仅当 1 秒内有新写入时刷新
}
扩展:fflush
的成本
- 系统调用开销 :
fflush
会触发用户态到内核态的上下文切换,频繁调用可能成为性能瓶颈。 - 磁盘 I/O 延迟 :
强制将缓冲区数据写入磁盘,涉及物理写操作,延迟较高。 - 优化平衡 :
通过_write_occurred
减少fflush
次数,在 数据安全性 (及时持久化)和 性能 之间取得平衡。
总结
_write_occurred
是一个轻量级的状态标志,通过简单的布尔值跟踪写入状态,实现了:
- 减少冗余 I/O 操作:避免无数据时的无效刷新。
- 降低系统调用开销:提升高吞吐场景下的性能。
- 保护资源:防止操作无效文件指针。
它是高性能日志库中常见的优化手段之一,尤其适用于需要平衡实时性和吞吐量的场景。
感触:对于一些好的三方库,还是有很多值得我们学习借鉴的知识点的,需要我们多想多思考多问一个为什么
【技术人的鼓励】❤️ 如果这篇文章对您有帮助,欢迎点击打赏按钮支持博主!您的鼓励是我持续输出优质技术内容的动力,哪怕只是1元也足以让我感受到这份珍贵的认可。💰