我有一个对性能高度敏感(读取低延迟要求)的 C++ 17 日志记录类,它的成员函数可以在本地记录或远程记录,具体取决于实现该类的标志。 “远程日志记录”或“本地日志记录”功能在构造对象时已完全定义。
代码看起来像这样
class Logger {
public:
Logger(bool aIsTx):isTx_(aIsTx) {init();}
~Logger() {}
uint16_t fbLog(const fileId_t aId, const void *aData, const uint16_t aSz){
if (isTx_)
// do remote logging
return remoteLog(aId, aData, aSz);
else
// do local logging
return fwrite(aData, aSz, 1,fd_[aId]);
}
protected:
bool isTx_
}
我想做的是
- 一些删除
if(isTx_)
的方法,以便在实例化时定义要使用的代码。 - 由于类对象被多个其他模块使用,我不想将类模板化,因为这将需要我将类的两个模板化实现包装在接口(interface)包装器中,这将导致每次调用 v-table成员函数被调用。
最佳答案
您不能“模板化”行为,因为您希望选择在运行时完成。
如果您因为性能问题想要去掉 if
,请放心,与磁盘访问或网络通信相比,它的影响可以忽略不计。虚函数调用也是如此。
如果您需要低延迟,我建议考虑异步日志记录:主线程只需将消息复制到内部缓冲区。内存比磁盘或网络快得多,因此延迟会少得多。然后,您可以有一个单独的服务线程等待缓冲区接收消息,并处理缓慢的通信。
作为奖励,您不需要在主线程中使用分支或虚函数,因为它是决定如何处理消息的服务线程。
然而,异步并不是一种简单的方法。有许多情况必须考虑:
- 如何同步对缓冲区的访问(我建议尝试使用无锁队列)。
- 应该允许缓冲区占用多少内存?没有限制,如果程序记录速度快于写入速度,它可能会消耗太多。
- 如果达到缓冲区限制,主线程应该做什么?它要么需要在处理缓冲区时回退到同步等待,要么需要丢弃消息。
- 程序崩溃时如何刷新缓冲区?如果不可能,那么最后的消息可能会丢失 - 这可能是您首先需要弄清楚程序崩溃的原因。
无论选择如何:如果性能至关重要,则尝试多种方法并进行衡量。
关于c++ - 如何根据构造函数参数为类成员函数模板化代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57983794/