高性能网络框架笔记二(阻塞与非阻塞、同步与异步)

在高性能网络架构笔记一中,我们聊完了网络数据的接收和发送。本章我们谈一下易混淆的概念:阻塞与同步,非阻塞与异步。

经过前面对网络数据包接收流程的介绍,在这里我们可以将整个流程总结为两个阶段:

  • 数据准备阶段:在这个阶段,网络数据包到达网卡,通过DMA的方式将数据包拷贝到内存中,然后经过硬中断,软中断,接着通过内核线程ksoftirqd经过内核协议栈的处理,最终将数据发送到内核Socket的接收缓冲区中。
  • 数据拷贝阶段:当数据到达内核Socket的接收缓冲区中时,此时数据存在于内核空间中,需要将数据拷贝到用户空间中,才能够被应用程序读取。

1、阻塞与非阻塞

阻塞与非阻塞到区别主要发生在第一个阶段:数据准备阶段。

当应用程序发起系统调用read时,线程从用户态转为内核态,读取内核Socket的接收缓冲区中的网络数据。

阻塞:

如果这时内核Socket的接收缓冲区没有数据,那么线程就会一直等待,直到Socket接收缓冲区有数据为止。随后将数据从内核空间拷贝到用户空间,系统调用read返回。

所以阻塞到特点是在第一阶段和第二阶段都会等待。

非阻塞:

阻塞和非阻塞主要的区分是在第一阶段:数据准备阶段。

  • 在第一阶段,当Socket的接收缓冲区中没有数据的时候,阻塞模式下应用线程会一直等待。非阻塞模式下应用线程不会等待,系统调用直接返回错误标志EWOULDBLOCK。
  • 当Socket的接收缓冲区中有数据的时候,阻塞和非阻塞的表现是一样的,都会进入第二阶段等待数据从内核空间拷贝到用户空间,然后系统调用返回。
  • 所以,从上述内容可以看出,非阻塞到特点是第一个阶段不会等待,但在第二个阶段还是会等待。

2、同步与异步

同步与异步主要的区别发生在第二阶段:数据拷贝阶段。

前面我们提到在数据拷贝阶段,主要是将数据从内核空间拷贝到用户空间。然后应用程序才可以读取数据。

当内核Socket的接收缓冲区有数据到达时,进入第二阶段。

同步:

同步模式在数据准备好后,是由用户线程的内核态来执行第二阶段。所以应用程序会在第二阶段发生阻塞,直到数据从内核空间拷贝到用户空间,系统调用才会返回。

Linux下的epoll和Mac下的kqueue都属于同步IO。

异步:

异步模式下是由内核来执行第二阶段的数据拷贝操作,当内核执行完第二阶段,会通知用户线程IO操作已完成,并将数据回调给用户线程。所以在异步模式下数据准备阶段和数据拷贝阶段均是由内核来完成,不会对应用程序操作任何阻塞。

机遇以上特征,我们可以看到异步模式需要内核的支持,比较依赖操作系统底层的支持。

在目前流行的操作系统中,只有Windows中的IOCP才真正属于异步IO,实现的也非常成熟。但Windwos很少用来做服务器使用。

而常用来作为服务器使用的Linux,异步IO机制实现还不够成熟,与NIO相比性能提升的也不够明显。

但Linux kernel在5.1版本由Facebook的大神Jens Axboe引入了新的异步IO库io_uring改善了原来Linux native AIO的一些性能问题。性能相比Epoll以及之前原生的AIO提高了不少,值得关注。

posted @ 2022-03-06 17:01  钟齐峰  阅读(147)  评论(0编辑  收藏  举报