并发方案

  1. PPC
  2. TPC
  3. preforking: 多个线程阻塞在同一个侦听端口上accept
  4. Multiplexing

"惊群"问题

同步和异步

同步和异步是针对应用程序和内核的交互而言的

  • 同步指的是用户进程触发I/O操作并等待或者轮询的去查看I/O操作是否就绪
  • 异步是指用户进程触发I/O操作以后便开始做自己的事情, 而当I/O操作已经完成的时候会得到I/O完成的通知.

阻塞和非阻塞

阻塞和非阻塞是针对于进程在访问数据的时候, 根据I/O操作的就绪状态来采取的不同方式, 是一种读取或者写入操作函数的实现方式

  • 阻塞方式下读取或者写入函数将一直等待
  • 非阻塞方式下读取或者写入函数会立即返回一个状态值

I/O模型

同步阻塞I/O

用户进程在发起一个I/O操作以后, 必须等待I/O操作的完成, 只有当真正完成了I/O操作以后, 用户进程才能继续运行.

同步非阻塞I/O

用户进程发起一个I/O操作以后边可返回做其它事情, 但是用户进程需要时不时的询问I/O操作是否就绪, 这就要求用户进程不停的去询问(会引入不必要的CPU资源浪费).

异步阻塞I/O

应用发起一个I/O操作以后, 不等待内核I/O操作的完成. 内核完成I/O操作以后会通知应用程序(这同步和异步最关键的区别,同步必须等待或者主动的去询问I/O是否完成) 之所以称之为阻塞, 是因为通过select等系统调用来完成的, 采用select函数的好处是它可以同时监听多个文件句柄, 从而提高系统的并发性.

异步非阻塞I/O

用户进程只需要发起一个I/O操作然后立即返回, 等I/O操作真正的完成以后, 应用程序会得到I/O操作完成的通知. 此时用户进程只需要对数据进行处理就好了, 不需要进行实际的I/O读写操作, 因为真正的I/O读取或者写入操作已经由内核完成了.

Reactor和Proactor模式

Reactor和proactor都是IO多路复用模式. I/O多路复用机制都依赖于一个事件多路分离器(Event Demultiplexer). 分离器可将来自事件源的I/O事件分发到对应的read/write事件处理器(Event Handler). 应用程序需预先注册需要处理的事件及其事件处理器(或回调函数)

Reactor模式

Reactor模式应用于同步I/O的场景

Reactor设计模式中的要素如下:

  1. Handles: 网络连接, 文件句柄等, 是事件源
  2. Synchronous Event Demultiplexer : 同步事件的派发, 如select调用.(epoll/kqueue/iocp).
  3. Initiation Dispatcher: 注册,移除和分派事件处理器
  4. Event Handler : 事件处理器

读取操作具体步骤:

  1. 应用程序注册读取事件和相关联的事件处理器
  2. 事件分离器等待事件的发生(Reactor负责)
  3. 当发生读取事件的时候, 事件分离器调用第一步注册的事件处理器(Reactor负责)
  4. 事件处理器首先执行实际的读取操作, 然后根据读取到的内容进行进一步的处理(用户处理器负责)

Proactor模式

Proactor模式应用于异步I/O场景

读取操作具体步骤:

  1. 应用程序初始化一个异步读取操作, 然后注册相应的事件处理器. 此时事件处理器 不关注读取就绪事件, 而是 关注读取完成事件(区别于Reactor的关键)
  2. 事件分离器等待读取操作完成事件
  3. 在事件分离器等待读取操作完成的时候, 操作系统调用内核线程完成读取操作, 并将读取的内容放入 用户传递过来的缓存区中
  4. 事件分离器捕获到读取完成事件后, 调用应用程序注册的事件处理器. 事件处理器直接从缓存区读取数据, 而不需要进行实际的读取操作

对比可以看出, Reactor和Proactor模式的主要区别就是真正的读取和写入操作是有谁来完成的: Reactor中需要应用程序自己读取或者写入数据; Proactor模式应用程序不需要进行实际的读写过程, 它只需要从缓存区读取或者写入即可, 操作系统会读取缓存区或者写入缓存区到真正的I/O设备.

results matching ""

    No results matching ""