Matthew Note

异步IO与协程框架

基于就绪通知的协程框架

  1. 首先需要包装read/write,在发生read的时候检查返回。如果是EAGAIN,那么将当前协程标记为阻塞在对应fd上,然后执行调度函数。
  2. 调度函数需要执行epoll(或者从上次的返回结果缓存中取数据,减少内核陷入次数),从中读取一个就绪的fd。如果没有,上下文应当被阻塞到至少有一个fd就绪。
  3. 查找这个fd对应的协程上下文对象,并调度过去。
  4. 当某个协程被调度到时,他多半应当在调度器返回的路上——也就是read/write读不到数据的时候。因此应当再重试读取,失败的话返回1。
  5. 如果读取到数据了,直接返回。

这样,异步的数据读写动作,在我们的想像中就可以变为同步的。而我们知道同步模型会极大降低我们的编程负担。

异步IO

Linux AIO

Blocking Non-Blocking
Synchronous Read/Write Read/Write(O_NONBLOCK)
Asynchronous IO Multiplexing AIO

基本方法:

1
2
3
4
5
6
7
int aio_read( struct aiocb *aiocbp );
int aio_error( struct aiocb *aiocbp );
ssize_t aio_return( struct aiocb *aiocbp );
int aio_write( struct aiocb *aiocbp );
int aio_suspend( const struct aiocb *const cblist[], int n, const struct timespec *timeout );
int aio_cancel( int fd, struct aiocb *aiocbp );
int lio_listio( int mode, struct aiocb *list[], int nent, struct sigevent *sig );

保存上下文的块:

1
2
3
4
5
6
7
8
9
10
11
12
struct aiocb {
int aio_fildes; // File Descriptor
int aio_lio_opcode; // Valid only for lio_listio (r/w/nop)
volatile void *aio_buf; // Data Buffer
size_t aio_nbytes; // Number of Bytes in Data Buffer
struct sigevent aio_sigevent; // Notification Structure
/* Internal fields */
...
};

Libeio

Libevent