您的位置:首页 > 理论基础 > 计算机网络

[转]网络服务器中生产者/消费者模型中的队列问题

2012-07-23 01:48 309 查看
感谢大熊同学为我解惑,这篇帖子的原创权属于大熊。

多线程模型的网络服务器中,一般有专门的网络IO线程,将请求放到请求队列中,此为生产者。然后多个工作线程从队列中获取其中一个请求,进行处理,此是消费者。

通常,通讯使用的队列为锁无关队列。且,为了避免CPU耗慢,当工作线程发现队列为空的时候,要睡眠一会儿。

要命的问题就出在这个睡眠上:

1、假设睡眠的时间是10ms,则当队列为空时,所有工作线程都陆续进入睡眠状态;

2、假设工作线程睡眠期间来了请求,则可能队列中的所有请求都会被延迟10ms才能处理到;

3、在整个服务器的运行周期里,队列为空的几率非常大,因此导致工作线程睡眠的几率也非常大。

毫无疑问,用以上的方法写服务器,延迟高,且性能上不去。

为什么不一有数据到队列,就有工作线程立即去处理呢?(且CPU不能因为轮询空跑)

传统的方法当然是semaphone, condition variable,大熊同学还提了一种开源代码中广泛采用的方案:

1. 用socketpair()系统调用产生两个fd,一个read_fd,一个write_fd

2. 生产者线程写数据到队列后,往write_fd中写入一个字节

3. 工作线程使用read_fd,然后使用epoll_wait等待read_fd上的事件

4. 当epoll_wait返回的时候,工作线程从队列中就能立即取到请求了

5. 工作线程最后还得从read_fd中读出一个字节

以上方案有什么好处呢?

1、队列的检查,不再是基于轮询-睡眠模式,而是基于事件的模式,有数据马上处理,延迟最小;

2、当多个工作线程存在的时候,每个线程都有监听自己的read_fd,所以可以实现按权重等各种复杂的调度算法;

缺点也还是有的:

1、每个工作线程创建的时候,都得调用socketpair()

2、每个线程要占用两个文件句柄

如果可以,后续希望可以测试一下:轮询-睡眠,socketpair()+epoll_wait(),semaphone,condition variable四种方式的性能的优劣。

http://hi.baidu.com/ah__fu/item/587e86d62f35cccb1b72b46e
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: