阻塞IO
Blocking IO
Last updated
Blocking IO
Last updated
在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:
用户进程调用了recvfrom这个系统调用
内核就开始了IO的第一个阶段:准备数据。对于Network IO来说,很多时候数据在一开始还没有到(比如,还没有收到一个完整的UDP包),这个时候内核就要等待足够的数据到来
在用户进程这边,整个进程会被阻塞
当内核一直等到数据准备好了,它就会将数据从内核中拷贝到用户内存, 然后内核返回结果
用户进程才解除block的状态,重新运行起来
所以,Blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block
几乎所有的程序员第一次接触到的网络编程都是从listen()、send()、recv() 等接口开始的,使用这些接口可以很方便的构建服务器/客户机的模型,然而大部分的socket接口都是阻塞型的,如下图:
PS:所谓阻塞型接口是指系统调用(一般是IO接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。
实际上,除非特别指定,几乎所有的IO接口 ( 包括socket接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。
一个简单的解决方案:
该方案的问题是:
改进方案:
改进后方案其实也存在着问题:
对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型也会遇到瓶颈,可以用非阻塞接口来尝试解决这个问题。