如何用 kevent() 替换 select() 以获得更高的性能?
Posted
技术标签:
【中文标题】如何用 kevent() 替换 select() 以获得更高的性能?【英文标题】:How do I replace select() with kevent() for higher performance? 【发布时间】:2011-04-22 14:22:46 【问题描述】:来自Kqueue Wikipedia Page:
Kqueue 在内核和用户空间之间提供高效的输入和输出事件管道。因此,可以在每次主事件循环迭代仅使用对 kevent(2) 的单个系统调用时修改事件过滤器以及接收挂起的事件。这与较旧的传统轮询系统调用(如 poll(2) 和 select(2))形成对比,后者效率较低,尤其是在轮询大量文件描述符上的事件时
听起来不错。我将 FreeBSD 用于我的服务器,并且我正在处理大量的网络套接字 fd - 对它们都使用 select() 并找出从谁那里读取数据。我宁愿使用 kevent() 调用来获得更高的性能,因为这就是它的用途!
我已经阅读了man page for kevent on FreeBSD here,但这对我来说很神秘,而且我没有找到很好的资源来解释它。使用 kevent 替换 select 的示例可以解决我的问题,也可以帮助我更好地了解如何使用 kevent()。
【问题讨论】:
【参考方案1】:首先,创建新的 kqueue:
int kq=kqueue();
现在在 kq 中注册你的 fd:
struct kevent kev;
kev.ident=your_fd;
kev.flags=EV_ADD | EV_CLEAR;
kev.filter=EVFILT_READ;
kev.fflags=0;
kev.data=0;
kev.udata=&your_data;
int res=kevent(kq,&kev,1,0,0,0);
最后,等待数据到达你的套接字:
struct kevent res_kevs[5];
int res=kevent(kq,0,0,res_kevs,5,0);
返回后,res_kevs[i].ident
将包含您的套接字描述符,res_kevs[i].data
- 准备读取的字节数。
有关更多详细信息和功能,请参阅 man kevent。
【讨论】:
感谢您第一个真正回答我的问题。只是为了澄清一下 - 我将为我的每个 fds(数千个)和一个 kqueue 设置一个 kevent 吗?这是通常的做法吗? 是的,因为每个 kevent() 调用只等待一个 kqueue。不过,您可以通过用 kq 填充 kev.ident 来将 kqueue 的描述符添加到另一个 kqueue 中。我不确定它究竟是如何工作的,因为由于某种原因它没有记录在案。【参考方案2】:你通常做的是使用libevent,,它会为你处理所有细节,这也意味着你可以将你的程序移到另一个具有不同方案(例如 Linux 和 epoll)的操作系统上来做某事类似。
【讨论】:
但是,除了使用 kevent 检查我是否从 fds 读取之外,我已经完成了这个 lib 所做的所有我关心的事情。我不想仅仅为此重写我的代码库来使用这个库,尽管如果我开始也许我会这样做。另外,我对“monkey.org”托管的东西感到畏缩 绝对不想要超集!虽然我可以查看这些软件并将答案汇总在一起,但我猜这并没有解决最初的问题 @Nektarios:它确实回答了它。如果您在 BSD 系统上使用其中一个库,它将使用 kevent 而不是 select。以上是关于如何用 kevent() 替换 select() 以获得更高的性能?的主要内容,如果未能解决你的问题,请参考以下文章
如何用MySQL REPLACE函数替换破碎的德语变音符号?