如何用 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() 以获得更高的性能?的主要内容,如果未能解决你的问题,请参考以下文章

GetX - 如何用新路线替换旧路线?

如何用第二列值替换星号

如何用MySQL REPLACE函数替换破碎的德语变音符号?

golang 程序配置文件中的 runtime.kevent 是啥?

在MYSQL中如何用一个字段的值替换另一个字段的值

MySql查询在Select中用空字符串替换NULL