在 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元也足以让我感受到这份珍贵的认可。💰