免费注册 查看新帖 |

Chinaunix

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

[C] epoll 多线程使用问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-12-06 10:29 |只看该作者 |倒序浏览
epoll 多线程使用问题


关于epoll 的基本用法,我相信大家很熟悉

简单描述一下
在epoll过程中, 我们基本是epoll_wait 等待到我们
想要的事件, 并且从epoll 返回的event 里面 找出事件,找到相应
的socket 和 unit, 进行操作

我简单描述一下 我的做法

map
  socket,  void *
  
  socket 代表 目前的socket
  void * 代表 和它相关的unit 对象
  
  当unit 希望等待socket 获取数据, 那么 我们首先将socket ,和读条件
  加入epoll 的fd. 当返回的时候, 我们可以从map 里,获取socket => unit 对象
  
  更好一点的做法, 我们可以将socket, unit 2者捆绑成一个结构, 将指针放入 epoll 的fd.
  在epoll 返回时候,我们就能直接使用,免除了 再次查找了。 但是这只是一个小的性能改进
  
  
  我目前的epoll 的处理方式 是
  
  while ( epoll_wait()) {
          // 遍历整个返回结果集 处理
          ...
          ...
          ...
          //1-3 将新socket 加入epoll_fd
  }
  
  
  很明显,这是一个低效的单线程处理过程。 即使你的cpu 核再多 也是无法多核的好处。
  所以  我想采用一个更高效的处理办法。
  
  第一步
    while ( epoll_wait()) {
          // 将相关的socket 从epoll 里面删除,不再关心它发生的事件
          // 如果不去除, 就会出现重入问题, 就是这个socket 新事件到达,
          // 而前一个线程可能还没有处理好。当然我们也可以用精确控制2个线程
          // 操作1 个对象,但这太容易出问题了。
         
         
          // 将结果集copy 出去
             
          ...
          ...
          ...
          //1-3  将新socket 加入epoll_fd
  }
  
  第二步
  
  多线程,以工作者的方式,不断的领取结果集,处理。
  
  处理完以后,根据情况,决定是否要再次加入epoll_fd.
  
  现在的问题是, 这样意味着,一次操作 就要进行一次出入epoll_fd 操作。
  比如 一个http 访问,正常情况,会返回5-8 次read 事件, 那么我就需要
  5-8 次的进入epoll_fd . 这样的效率是否会很低。
  
  epoll_fd 是在任何时候都可以加入的吗? 我目前做法比较固定,需要
  在epoll_wait 返回后,才进行, 也就是在1-3 的地方进行。 如果为提高性能。
  多线程必然在epoll_wait 没有返回的情况下,加入,所以这样是否安全,
  我并不知道(我尝试过,有些问题,但不敢保证是epoll本身造成的)。
  而且这样也会带来一些 事务不完整的问题。

  无论如何 这都是一个新的性能瓶颈
  
  不知道大家的epoll 架构是怎么做的? 我发现在这点上windows 的完成端口到是
  简单了很多, 它简单的一次返回,不会有这个问题。
  

论坛徽章:
0
2 [报告]
发表于 2007-12-06 10:49 |只看该作者
使用epoll的ET模式,同一事件不会返回多次,针对每次事件由一个线程来处理,然后再做线程间的同步

论坛徽章:
0
3 [报告]
发表于 2007-12-06 11:27 |只看该作者
原帖由 cugb_cat 于 2007-12-6 10:49 发表
使用epoll的ET模式,同一事件不会返回多次,针对每次事件由一个线程来处理,然后再做线程间的同步


.... 本来就是ET 模式。  同一个事件只返回一次。  每次事件由一个线程来处理。 线程本身处理时间由于业务长短不一,和操作系统处理就是无法统计的。

需要同步的情况,就会出现 最短处理的线程等最长处理线程。这个性能拉得更厉害了。

如果你愿意 可以画画你的逻辑图。

使用epoll的ET模式,同一事件不会返回多次 再说一点。  当和你联系的对方, 这样发送数据, 你是肯定需要多次返回read 的

它 send 1 字节 sleep 20 秒。 再send 1字节 sleep 20秒.....

论坛徽章:
0
4 [报告]
发表于 2007-12-06 11:30 |只看该作者
我没太明白楼主要表达什么意思,楼主说的性能瓶颈是哪儿?

论坛徽章:
0
5 [报告]
发表于 2007-12-06 12:49 |只看该作者
普通的情况

while (。。。) {

  .....

  假设 10个 返回结果 那么处理时间是1 s  , 那么一个循环 就是10s

  如果有一个结果是 2s 完成 那就是11s

}

我的想法
while () {
  //
.....

}

100 个返回结果。 如果100个线程, 那么只需要 1s. 最多的是2s

问题是在 处理的1s 中, while () 会继续走。 不会锁死。

但是线程在处理完以后, 需要重新加入到epoll_fd.  所以会多100 次epoll_remov 和100 次
epoll_add 操作。  这个操作如何做。 对系统性能影响有多大。 有人知道吗?  而且加入的时候
epoll_fd 能同时进行epoll_wait 操作吗? 不能的话,就需要一个同步。 这就是一个瓶颈

论坛徽章:
0
6 [报告]
发表于 2007-12-06 17:48 |只看该作者
epoll_fd 能同时进行epoll_wait 操作吗?应该没什么问题,如果这个也成问题,那短联接的服务怎么用epoll,如http

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
7 [报告]
发表于 2007-12-07 10:39 |只看该作者
但是线程在处理完以后, 需要重新加入到epoll_fd.  所以会多100 次epoll_remov 和100 次
epoll_add 操作。  这个操作如何做。 对系统性能影响有多大。 有人知道吗?  


这里为什么要重新加入epoll_fd ? 线程得到fd 直接recv 或send 。如果出现错误你才调用epoll_remove,

论坛徽章:
0
8 [报告]
发表于 2007-12-07 15:07 |只看该作者
如果想再细化的话 , 可以启动三个线程,一个负责socket联接  , 一个负责接受数据  , 一个负责数据发送...三个都用epoll....

论坛徽章:
0
9 [报告]
发表于 2007-12-07 16:01 |只看该作者
原帖由 cookis 于 2007-12-7 10:39 发表


这里为什么要重新加入epoll_fd ? 线程得到fd 直接recv 或send 。如果出现错误你才调用epoll_remove,



这里为什么要重新加入epoll_fd ? 因为多线程。 线程在处理的时候, epoll_Wait 将再次被调用。 仔细看我的图。 不删除, 就是原始模式

论坛徽章:
0
10 [报告]
发表于 2007-12-07 16:01 |只看该作者
原帖由 ruchong 于 2007-12-7 15:07 发表
如果想再细化的话 , 可以启动三个线程,一个负责socket联接  , 一个负责接受数据  , 一个负责数据发送...三个都用epoll....



但是 接收了数据的时候,还是要从epoll 里面出来, 否则还是需要epoll 循环等待的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP