我正在为我的应用程序设计类(网络工具)。我这个基类:
class Descriptor
{
// ...
public:
virtual void data_read (void);
virtual void data_write (void);
virtual void data_error (void);
protected:
int socket_descriptor;
// ...
}
class TcpClient :
public Descriptor
{
// ...
}
许多类都基于描述符。我使用epoll监视套接字的事件。当我想在TcpClient对象上查找事件时,我将对象的套接字和指向此对象的指针添加到epoll,代码:
epoll_event descriptor_events;
descriptor_events.events = EPOLLIN;
descriptor_events.data.fd = this->socket_descriptor;
descriptor_events.data.ptr = this;
epoll_ctl (epoll_descriptor, EPOLL_CTL_ADD, this->socket_descriptor, &descriptor_events);
我以这种方式在单独的线程中发送epoll事件:
Descriptor *descriptor (NULL);
// ...
return_value = epoll_wait (epoll_descriptor, events, 64, -1);
while (i < return_value)
{
descriptor = (Descriptor *) (events [i]).data.ptr;
if ((events [i]).events & EPOLLOUT)
descriptor->data_write ();
if ((events [i]).events & EPOLLIN)
descriptor->data_read ();
if ((events [i]).events & EPOLLERR)
descriptor->data_error ();
i++;
}
程序将在epoll线程中处理大量数据,因此意味着虚拟函数将在那里被多次调用。我想知道这个解决方案的运行时成本。
我也在考虑其他两个实现(但是我不确定它们是否更快):
typedef void (*function) (Descriptor *) EventFunction;
class Descriptor
{
// ...
public:
EventFunction data_read;
EventFunction data_write;
EventFunction data_error;
protected:
Descriptor (EventFunction data_read,
EventFunction data_write,
EventFunction data_error);
int socket_descriptor;
// ...
}
或使用CRTP。
也许你有其他想法实现这个?
答案 0 :(得分:2)
除非另有证明,否则您的原始设计对我来说很好。
优化的第一条规则是先测量,然后只修复真正存在的热点。你的代码花费时间的地方会让你感到惊讶。关注虚函数和函数指针之间的区别几乎肯定是过早的优化。在这两种情况下,编译器都会生成跳转到函数指针的代码,但是对于虚函数,编译器必须首先查找vtable。编写惯用的C ++代码来执行您想要的操作,然后在遇到性能问题时对其进行概要分析。
(我对你的班级Descriptor
有一个评论:除非你计划使用通用的data_read(),data_write()和data_error()方法,否则我建议你使用纯虚方法。)
答案 1 :(得分:1)
老实说,优化此代码的最佳选择可能是将其完全替换为Boost ASIO。如上所述,您实际上是在重新实施经过严格审查且经过充分测试的ASIO库。除非你绝对肯定你必须推出自己的I / O库,否则你可能会节省大量的开发工作。通过使用现有解决方案来优化时间。
答案 2 :(得分:0)
在don't reinvent the wheel保护伞下,我建议查看Boost.Asio,因为它提供了示例代码中描述的大部分功能。