Concurrency

如何实现高并发

I/O 策略的选择

首先,有哪些I/O model 可以选择?

UNIX Netwrok Programming中,列出了以下5种I/O模型:

blocking I/O

nonblocking I/O

I/O multiplexing (select and poll)

singnal driven I/O (SIGIO)

asynchronous I/O (the POSIX aio_functions)

我们先不仔细研究,先看下 The C10K problem中,列出了哪些 I/O Strategies。

1 一个线程服务多个客户端,使用非阻塞I/O和水平触发的就绪通知

2 一个线程服务多个客户端,使用非阻塞I/O和边缘触发的就绪通知

3 一个服务线程服务多个客户端,使用异步I/O

4 一个服务线程服务多个客户端,使用阻塞I/O

5 把服务代码编译进内核

1,2 都是使用单个线程来关注一些列nonblocking sockets,看它们何时ready for I/O。但是1,2所说的非阻塞I/O不是上面列出的5种I/O模型中的第二个,它指的应该是第一种的对立面,主要包含了第三种,既I/O multiplexing模式。

1 一个线程服务多个客户端,使用非阻塞I/O和水平触发的就绪通知

实现方式:

  • 传统的select:受限于句柄个数
  • 传统的poll:性能低,因为扫码大量的描述符很耗费时间
  • kqueue(level-trigger):for FreeBSD

2 一个线程服务多个客户端,使用非阻塞I/O和边缘触发的就绪通知

实现方式:

  • kqueue(edge-trigger):
  • epoll:Linux2.6中推荐使用的edge-triggered poll
  • Realtime Signal:Linux2.4中推荐使用的edge-triggered poll

####关于水平触发边缘触发

水平触发(level-triggered)——只要满足条件,就触发一个事件(只要有数据没有被获取,内核就不断通知你);边缘触发(edge-triggered)——每当状态变化时,触发一个事件。

select,poll,Epoll区别:

select poll Poll
支持最大连接数 1024(x86) 2048(x64) 无限制 无限制
I/O效率 每次调用遍历所有 每次调用遍历所有 使用“事件”通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到rdllist里面,这样epoll_wait返回的时候我们就拿到了就绪的fd。时间发复杂度O(1)
fd拷贝 每次调用需要拷贝 每次调用拷贝 调用epoll_ctl时拷贝进内核并由内核保存,之后每次epoll_wait不拷贝

3一个服务线程服务多个客户端,使用异步I/O

该方法目前还没有在Unix上普遍的使用,可能因为很少的操作系统支持异步I/O。在标准Unix下,异步I/O是由“aio_”接口 提供的,既上面5种模型中的最后一种:asynchronous I/O 。它把一个信号和值与每一个I/O操作关联起来。信号和其值的队列被有效地分配到用户的 进程上。

关于异步I/O和同步I/O

UNIX Netwrok Programming中有这样的描述:

1
2
3
POSIX defines these two terms as follows:
A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes.
An asynchronous I/O operation does not cause the requesting process to be blocked.

所以,上面的5中模型中,1~4是同步I/O,5才是异步I/O。

关于阻塞I/O和非阻塞I/O

阻塞I/O :BIO , 非阻塞I/O:NIO ,

一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作,阻塞IO和非阻塞IO的区别在于第一步:发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO;如果不阻塞,那么就是非阻塞IO

4一个服务线程服务多个客户端,使用阻塞I/O

一个线程一个socket?

5 把服务代码编译进内核

并发模型

实现并发的途径有两种,基于线程和基于事件。

并发和并行

并发concurrency属于问题域(problem domain), 并行parallelism属于( solution domain)。并行和并发的区别在于有无状态,并行计算适合无状态应用,而并发解决的是有状态的高性能; 有状态要着力解决并发计算,无状态要着力并行计算。

参考: