免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5887 | 回复: 8
打印 上一主题 下一主题

[其他] epoll 惊群相关 [复制链接]

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-05-09 18:40 |只看该作者 |倒序浏览
本帖最后由 zylthinking 于 2013-05-09 18:49 编辑

重温 epoll, 同时给之前研究 epoll 的几位看看, 上次读 epoll 还是因为那几个帖子。

epoll 现在仍然还是有惊群现象的, 但这不是大问题, 因为导致惊群出现的用法已经怎么看怎么不合理了: 如果你将同一个 fd 加入不同的 epollfd, 那么不管你怎么设置属性, 包括前段时间热炒的大招  EPOLLONESHOT, 都避免不了。 好的是, 谁也不会这么干。

epoll 实现基本数据结构有三个, eventpoll, epoll_item, epoll_entry
eventpoll 对应 epollfd
epoll_item 对应加入到某个 epoll 的 fd 实例, 如果同一个 fd 加入多个 epollfd, 则存在多个 epoll_item
epoll_entry 和 epoll_item 一一对应。

相互之间关系为, eventpoll 中保存 epoll_item 链表, epoll_item 和 epoll_entry 一一对应, 通过 epoll_entry 加入到 fd 对应的 file_struct 的 wait 队列。
一旦 fd 有事件了, 通过 wait_list 到达 epoll_entry 然后最终到达 eventpoll, 然后在 epoll_wait 的线程唤醒, 将事件写入用户空间。
这里有个 eventpoll 级别的锁,因此就算多个 epoll_wait 唤醒, 最终只有一个会得到事件, 剩下的空转一圈接着睡眠, 这就是 epoll_wait 为何不惊群的原因, 但要注意不惊群是针对同一个 eventpoll 而言的, 对不同 eventpoll, 是没办法的。
EPOLLONESHOT 是 epoll_item 级别的, 设置方是获得了事件的那个线程, 由于 epoll_item 局限于 eventpoll, 因此 EPOLLONESHOT 也不能阻止同时存在于另一个 epollfd 的 fd 上出现事件, 而导致惊群。

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
2 [报告]
发表于 2013-05-09 21:30 |只看该作者
right。

"因此就算多个 epoll_wait 唤醒, 最终只有一个会得到事件, 剩下的空转一圈接着睡眠,"
-->这里应该不会有多个唤醒,我记得是唤醒单个

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
3 [报告]
发表于 2013-05-10 06:49 |只看该作者
chenzhanyiczy 发表于 2013-05-09 21:30
right。

"因此就算多个 epoll_wait 唤醒, 最终只有一个会得到事件, 剩下的空转一圈接着睡眠,"


在内核中空转, 用户层怎么会知道

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
4 [报告]
发表于 2013-05-10 10:06 |只看该作者
就是说无论一个fd被几个线程几个epollset注册了, 并发的话内核里都避免不了空转, 但应用层看起来是防惊群的.

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
5 [报告]
发表于 2013-05-10 10:27 |只看该作者
zylthinking 发表于 2013-05-10 06:49
在内核中空转, 用户层怎么会知道


错了, 没看仔细, 内核里面也不会空转, wake up 是 exclusive 的, 意味着只有对列中第一个线程被唤醒。
但也应该有并发竞争的情况, 出现于在唤醒的同时存在至少一个刚刚进入 epoll_wait 还没有来得及进入 wait list 睡眠, 这样这个刚刚进入的线程有可能会和被唤醒的线程同时竞争事件, 避免这个竞态的是 epollevent 里面的锁

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
6 [报告]
发表于 2013-05-10 10:31 |只看该作者
本帖最后由 zylthinking 于 2013-05-10 10:41 编辑
linux_c_py_php 发表于 2013-05-10 10:06
就是说无论一个fd被几个线程几个epollset注册了, 并发的话内核里都避免不了空转, 但应用层看起来是防惊群的 ...


一个 fd 被多于一个 epollset 注册, 则无法防止应用层惊群。
唯一避免的办法是不同时注册于多于一个 epollset.
其实想想如果在实现时不使用一个 fd 可能对应多个 epitem 结构, 而是多个 epollevent 共享同一个 epitem, 则可以实现即便同时注册于多个 epollset 也不会产生应用层惊群。 不知到 epoll 为什么要这么实现, 或者有难以绕过去的困难吧, 看代码看到的理解毕竟浅薄。

上面提到的内核中可能存在的空转发生于对同一个 epollset 进行 wait 的多个线程; 但也不是常见, 看楼上

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
7 [报告]
发表于 2013-05-10 11:18 |只看该作者
噢噢,那就是和之前的认识一致,多个epoll肯定是惊群的,但一个epoll多个线程无论是否EPOLLONESHOT都可能会空转,但注册了EPOLLONESHOT后对应用层透明。

我之前也看了一下epoll的代码,不过只是想看看是不是有锁,另外看了一下EPOLLERR和EPOLLHUP是不是默认注册,发现只有在EPOLLONESHOT返回后这两个标记才能真正清楚,所以做leader-follower/half-sync-half-async都有必须用EPOLLONESHOT来清理标记。

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
8 [报告]
发表于 2013-05-10 14:21 |只看该作者
本帖最后由 chenzhanyiczy 于 2013-05-10 14:30 编辑
zylthinking 发表于 2013-05-10 10:27
错了, 没看仔细, 内核里面也不会空转, wake up 是 exclusive 的, 意味着只有对列中第一个线程被唤醒 ...



特意查了一下。之前的说法有点出入。

在linux 2.6.18下,会发现惊群,因为加入等待队列的时候,没有设置exclusive。代码如下:
__add_wait_queue(&ep->wq, &wait);
而之后的版本(具体哪个版本开始就不知道)采用的是如下:
__add_wait_queue_exclusive(&ep->wq, &wait);
这样避免了惊群。

同时你后面说的那个情况,就不是惊群问题了。惊群的前提是:笼统地说,大家都在睡眠等待资源的可用

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
9 [报告]
发表于 2015-07-03 13:35 |只看该作者
linux_c_py_php 发表于 2013-05-10 10:06
就是说无论一个fd被几个线程几个epollset注册了, 并发的话内核里都避免不了空转, 但应用层看起来是防惊群的 ...


http://bbs.chinaunix.net/thread-4181206-1-1.html
看日志,明显的惊群了。
Linux mtrlin 2.6.32-279.el6.x86_64 #1 SMP Fri Jun 22 12:19:21 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP